次のシェルスクリプトがあります。目的は、ターゲットファイルの各行(そのパスはスクリプトへの入力パラメーターです)をループし、各行に対して作業を行うことです。現在、ターゲットファイルの最初の行でのみ機能し、その行が処理された後に停止するようです。スクリプトに問題はありますか?
#!/bin/bash
# SCRIPT: do.sh
# PURPOSE: loop thru the targets
FILENAME=$1
count=0
echo "proceed with $FILENAME"
while read LINE; do
let count++
echo "$count $LINE"
sh ./do_work.sh $LINE
done < $FILENAME
echo "\ntotal $count targets"
do_work.sh
、いくつかのssh
コマンドを実行します。
問題は、do_work.sh
がssh
コマンドを実行し、デフォルトでssh
が入力ファイルであるstdinから読み取ることです。その結果、ssh
がファイルの残りを消費し、whileループが終了するため、処理された最初の行のみが表示されます。
これを防ぐには、-n
オプションをssh
コマンドに渡し、stdinの代わりに/dev/null
から読み取るようにします。
ssh -nオプションは、HEREdocを使用して出力を別のプログラムにパイプするときに、sshの終了ステータスをチェックしません。そのため、/ dev/nullを標準入力として使用することをお勧めします。
#!/bin/bash
while read ONELINE ; do
ssh ubuntu@Host_xyz </dev/null <<EOF 2>&1 | filter_pgm
echo "Hi, $ONELINE. You come here often?"
process_response_pgm
EOF
if [ ${PIPESTATUS[0]} -ne 0 ] ; then
echo "aborting loop"
exit ${PIPESTATUS[0]}
fi
done << input_list.txt
より一般的には、ssh
に固有ではない回避策は、while
ループの入力を消費する可能性のあるコマンドの標準入力をリダイレクトすることです。
while read -r LINE; do
let count++
echo "$count $LINE"
sh ./do_work.sh "$LINE" </dev/null
done < "$FILENAME"
ここで</dev/null
を追加することが重要です(ただし、修正された引用もいくらか重要です。 シェル変数を引用符で囲む場合 も参照してください)。 read -r
なしで得られる従来のわずかに奇妙な動作を特に必要としない限り、-r
を使用する必要があります。
ssh
にある程度固有のソートの別の回避策は、ssh
コマンドの標準入力が固定されていることを確認することです。変更することにより
ssh otherhost some commands here
代わりにヒアドキュメントからコマンドを読むと、(この特定のシナリオでは)コマンドのssh
の標準入力が便利に結び付けられます:
ssh otherhost <<'____HERE'
some commands here
____HERE