概要

概要

ポート番号をパラメータとして使用するスクリプトを作成しようとしています。何も割り当てられていない次のポートを返し、ファイルを使用して確認します/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

ループが見えるほぼ美しい。$foundnull の場合に備えて、テストでエンティティを参照する必要があります。また、port=not を使用して割り当てます$port=(しかし、上記で正しい形式を使用したため、ただ誤字のようです)。最後は$($port+1)(例えば if portis 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
}

おすすめ記事