
サービスを展開するためのBashスクリプトがあります。サービスの複数のインスタンスを起動するために使用されるポートを指定するには、追加のコマンドラインパラメータ形式で更新する必要があります。このパラメーターは、カンマ区切りポートとコロン区切りポートの範囲を受け入れます。つまり、一部の有効な値は次のとおりです。
5001,5002,5003,5004
5001:5004
2003,4001:4008
1337,2300:2340,5000,5008
値を配列として読み取って範囲を拡張する必要があります(つまり、2003,4001:4008
値配列の場合と同じでなければなりません[2003,4001,4002,4003,4004,4005,4006,4007,4008]
)。
Bashだけを使用してこれらすべての状況を処理する効率的な方法が見つからないようです(Perlでは許可されていませんが、awkでは許可されています)。ティア。
答え1
最新のawk
実装を使用してください。
awk -v RS='[,\n]' -F: 'NF == 1; NF == 2 { for (i = $1; i <= $2; ++i) print i }'
上記のコマンドawk
は、説明した形式で1行または行セットを読み取り、各コンマまたは改行で区切られた値を「レコード」として処理し、各コロンで区切られた文字列を「フィールド」として扱います。
レコードにフィールドが1つしかない場合(NF == 1
)、そのまま印刷します。入力に含まれる範囲以外の値の1つ。
レコードに2つのフィールド(NF == 2
)がある場合は、最初のフィールドから2番目のフィールドまでの数字を印刷します。
テスト:
$ echo '2003,4001:4008' | awk -v RS='[,\n]' -F: 'NF == 1; NF == 2 { for (i = $1; i <= $2; ++i) print i }'
2003
4001
4002
4003
4004
4005
4006
4007
4008
その後、生成されたリストを任意の方法で使用できます。例えば、
#!/bin/sh
printf '%s\n' "$1" |
awk -v RS='[,\n]' -F: 'NF == 1; NF == 2 { for (i = $1; i <= $2; ++i) print i }' |
xargs -I {} some_executable ...options... --port={}
some_executable ...options... --port={}
これはコードの各数値出力に対して一度実行され、数値に置き換えられますawk
。{}
このawk
コードは、スクリプトの最初の引数として指定された文字列を取得します。
提供されたパラメーターについては検証は行われません。
答え2
データを制御できるため、パラメータと中括弧拡張を使用できます。引用符なしで変数を使用して目的のeval
効果を得たので、悪意のある入力を防ぐためにGuard句を追加しました。
expand() {
if [[ $1 == *[^,:[:digit:]]* ]]; then
echo "unexpected characters detected in argument" >&2
return 1
fi
local IFS=,
for val in $1; do
if [[ $val == *:* ]]; then
eval "printf '%s\n' {${val/:/..}}"
else
echo "$val"
fi
done
}
その後、データでテストしてみてください。
while read line; do
readarray -t values < <(expand "$line")
declare -p values
done << 'END'
5001,5002,5003,5004
5001:5004
2003,4001:4008
1337,2300:2340,5000,5008
1,2,3,$(some malicious command),4
END
明らかにする
declare -a values=([0]="5001" [1]="5002" [2]="5003" [3]="5004")
declare -a values=([0]="5001" [1]="5002" [2]="5003" [3]="5004")
declare -a values=([0]="2003" [1]="4001" [2]="4002" [3]="4003" [4]="4004" [5]="4005" [6]="4006" [7]="4007" [8]="4008")
declare -a values=([0]="1337" [1]="2300" [2]="2301" [3]="2302" [4]="2303" [5]="2304" [6]="2305" [7]="2306" [8]="2307" [9]="2308" [10]="2309" [11]="2310" [12]="2311" [13]="2312" [14]="2313" [15]="2314" [16]="2315" [17]="2316" [18]="2317" [19]="2318" [20]="2319" [21]="2320" [22]="2321" [23]="2322" [24]="2323" [25]="2324" [26]="2325" [27]="2326" [28]="2327" [29]="2328" [30]="2329" [31]="2330" [32]="2331" [33]="2332" [34]="2333" [35]="2334" [36]="2335" [37]="2336" [38]="2337" [39]="2338" [40]="2339" [41]="2340" [42]="5000" [43]="5008")
unexpected characters detected in argument
declare -a values=()
答え3
for j in `cat file`; do echo $j | perl -pne "s/,/\n/g"| awk -F ":" '/:/{for(i=$1;i<=$2;i++)print i}1'|sed '/:/d'| awk 'ORS=" "'; echo -e "\n";done
output
5001 5002 5003 5004
5001 5002 5003 5004
2003 4001 4002 4003 4004 4005 4006 4007 4008
1337 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323