ポート番号をパラメータとして使用するスクリプトを作成しようとしています。何も割り当てられていない次のポートを返し、ファイルを使用して確認します/etc/services
。ポートが使用中の場合(つまり、ドキュメントにリストされている)、ポートを追加して再試行します。このスクリプトが「found」から何でも返すことはできないようです。常に0に等しいので、whileループには入りません。私は何が間違っていましたか?
#!/bin/bash
port=$1
found=$(cat /etc/services | grep -o '[[:space:]]$port/' | wc -l)
while [ $found -ge 1 ]; do
$port=$($port+1)
#done
echo "found: $found"
echo "port: $port"
(以前のコメントは無視してくださいdone
。問題ありません。)
答え1
概要
このスクリプトにはいくつかのマイナーなバグがあり、いくつかのスタイルを変更する必要があります。元の内容を1行ずつ見てみましょう。
#!/bin/bash
port=$1
一般的な#!
道と簡単な使命で、私たちは良い出発をしました。
found=$(cat /etc/services | grep -o '[[:space:]]$port/' | wc -l)
この行には最初は気付かない小さな問題があります。$port
だからこそ強力な参照、、'…$port'
対応する値には拡張されません。あなたは使いたいでしょう弱い引用符逆に、"…$port"
。さらに、cat
ここでは実際には必要ありません。 grep
ファイル名を引数として受け入れますが、そうでない場合はいつでも使用できます。リダイレクト(grep 'pattern' < /etc/services
)。また、grep -c
一致する行の数が記録されるため、wc -l
これも重複します。
while [ $found -ge 1 ]; do
$port=$($port+1)
done
ループが見えるほぼ美しい。$found
null の場合に備えて、テストでエンティティを参照する必要があります。また、port=
not を使用して割り当てます$port=
(しかし、上記で正しい形式を使用したため、ただ誤字のようです)。最後は$($port+1)
(例えば if port
is 22
)「コマンドの出力22+1
」を意味します。明らかに、あなたは22+1
非常に似た「算術表現の結果」が欲しいです$(($port+1))
。
echo "found: $found"
echo "port: $port"
この行はそのままにしてください。
論理を考える
さて、上記のすべてを変更すると、プログラムは構文的にそうですね。それでも好きなようにはなりません。 「正しい」出力をリストしていないので、次のことを望んでいるとします。
found: <the number of occurrences of $1 in /etc/services>
port: <the next free port>
これらの仮定が間違っている場合は、コメントでお知らせください。それに応じて修正します。
ポートが提供されると、スクリプトは決して返されません。する/etc/services
更新していないため表示されますfound
。したがって、found=…
その行をループにコピーするのが賢明だと思うかもしれませんが、そうではありません!これにより、スクリプトは常にを返しますfound: 0
。私の考えに最適な方法は機能:
found () {
grep -co "[[:space:]]$1/" /etc/services
}
ただし、関数の終了値を条件として直接使用できるようになりました。出力とともに表示されないように、出力を無音に設定する必要があります。これで-co
フラグは不要になりますが、次のことを行います-q
。
while found "$port"; do
次に、入力ポートの発生回数を返すには、次のようにします。
echo "found: $(found "$1")"
またはを使用できますprintf
。
それらを一つにまとめる
私はこれがあなたが書いたいスクリプトだと思います。
#!/bin/sh
found () {
grep -q "[[:space:]]$1/" /etc/services
}
port=$1
while found "$port"; do
port=$(($port+1))
done
printf 'found: %d\nport %d\n' "$(found "$1")" "$port"
ボーナス
awk
この記事を書いたときの私の最初の反応は、与えられたパターンに一致する行数を数えることですgrep
。その後、プログラム全体を使用できると思いましたawk
。ボーナスとしてここに実装があります(ここでは/etc/services
ポート番号でソートされていると仮定しています)。
#!/usr/bin/awk -f
BEGIN {
FS = "[ \t/][ \t/]*"
ARGC = 2
PORT = ARGV[1]
OPORT = PORT
ARGV[1] = "/etc/services"
}
($2 == OPORT) {
FOUND = FOUND + 1
}
(NEXT == 0 && NR > 1 && $2 > PORT) {
NEXT = ($2 > PORT + 1) ? PORT + 1 : NEXT
PORT = $2
}
END {
printf "found: %d\nport: %d\n", FOUND, (FOUND == 0) ? OPORT : NEXT
}
答え2
数学の部分を減算すると、目的の操作を実行しますが、ロジックを実装するために「while」ループ条件の代わりに「if」ステートメントを使用する高速で汚れたPOCがあります。
#!/bin/bash
port=$1
echo $port | while read a; do
found=$(cat /etc/services | grep -Eo '[0-9]{1,5}/' | sed 's/^/ /' | grep ' '$a'/')
if [[ $found ]];
then echo port $a is being used
else echo port $a is not being used
fi
done
編集:問題は$ found変数で発生します。 grepの一重引用符のために$portは文字通り解釈されるので、 "80/"の代わりに "$port/"文字列をgrepします。回避策:一重引用符を二重引用符に置き換えます。
検索=$(cat /etc/services | grep -o "[[:space:]]$port/" | wc -l)