139

次のシェルスクリプトがあります。目的は、ターゲットファイル(パスはスクリプトへの入力パラメーター)の各行をループし、各行に対して作業を行うことです。現在、ターゲットファイルの最初の行でのみ機能し、その行が処理された後に停止するようです。スクリプトに何か問題がありますか?

#!/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コマンドを実行します。

4

5 に答える 5

227

問題は、コマンドをdo_work.sh実行sshし、デフォルトsshで入力ファイルであるstdinから読み取ることです。その結果、コマンドがファイルの残りの部分を消費し、whileループが終了するため、処理された最初の行のみが表示されます。

これは、だけでなくssh、、、、などを含むstdinを読み取るすべてのコマンドでmplayer発生ffmpegHandBrakeCLIます。

これを防ぐ-nには、コマンドにオプションを渡して、stdinの代わりにssh読み取り元に設定します。/dev/null他のコマンドにも同様のフラグがあります。または、を普遍的に使用できます< /dev/null

于 2012-12-10T11:56:30.357 に答える
16

非常に簡単で堅牢な回避策は、コマンドが入力を受け取るファイル記述子を変更することです。read

-uこれは、への引数readと のリダイレクト演算子の2 つの変更によって実現され< $FILENAMEます。

BASH では、デフォルトのファイル記述子の値 (つまり-uinの値read) は次のとおりです。

  • 0 = 標準入力
  • 1 = 標準出力
  • 2 = 標準エラー

9したがって、楽しみのために、他の未使用のファイル記述子を選択してください。

したがって、次の方法で回避できます。

while read -u 9 LINE; do
   let count++
   echo "$count $LINE"
   sh ./do_work.sh $LINE
done 9< $FILENAME

2 つの変更点に注意してください。

  1. readになるread -u 9
  2. < $FILENAMEになる9< $FILENAME

ベスト プラクティスとして、whileBASH で記述したすべてのループに対してこれを行います。を使用してネストされたループがある場合は、ループごとreadに異なるファイル記述子(9、8、7、...) を使用します。

于 2021-02-12T21:16:34.837 に答える