解決策

解決策

servers.txtサーバーのリストを含むファイルがあります。

server1.mydomain.com
server2.mydomain.com
server3.mydomain.com

ファイルを1行ずつ読み、各行whileをエコーすると、すべてが期待どおりに機能します。すべての行が印刷されます。

$ while read HOST ; do echo $HOST ; done < servers.txt
server1.mydomain.com
server2.mydomain.com
server3.mydomain.com

ただし、すべてのサーバーでSSHを介してコマンドを実行しようとすると、ループは突然while動作を停止します。

$ while read HOST ; do ssh $HOST "uname -a" ; done < servers.txt
Linux server1 2.6.30.4-1 #1 SMP Wed Aug 12 19:55:12 EDT 2009 i686 GNU/Linux

これは、すべてのサーバーではなく、リストの最初のサーバーにのみ接続されます。私はここで何が起こっているのか理解していません。誰かがこれを説明できますか?

forループを使用するとうまく機能するため、これはさらに奇妙です。

$ for HOST in $(cat servers.txt ) ; do ssh $HOST "uname -a" ; done
Linux server1 2.6.30.4-1 #1 SMP Wed Aug 12 19:55:12 EDT 2009 i686 GNU/Linux
Linux server2 2.6.30.4-1 #1 SMP Wed Aug 12 19:55:12 EDT 2009 i686 GNU/Linux
Linux server3 2.6.30.4-1 #1 SMP Wed Aug 12 19:55:12 EDT 2009 i686 GNU/Linux

ssh他のコマンドは正しく機能するため、そのコマンドにのみ適用する必要がありますping。たとえば、次のようになります。

$ while read HOST ; do ping -c 1 $HOST ; done < servers.txt

ベストアンサー1

ssh標準入力の残りの部分を読んでいます。

while read HOST ; do … ; done < servers.txt

read標準入力から読み出します。<ファイルから標準入力をリダイレクトします。

残念ながら、実行しようとしているコマンドは標準入力も読み取るため、最終的にファイルの残りの部分が消えてしまいます。以下を使用して明確に表示できます。

$ while read HOST ; do echo start $HOST end; cat; done < servers.txt 
start server1.mydomain.com end
server2.mydomain.com
server3.mydomain.com

残りの2行がどのように削除され、catエコーされているかを確認してください。 (期待どおりに完了すると、各行にはホストの周りに「開始」と「終了」が表示されます。)

なぜfor動作しますか?

あなたのfor回線は標準入力にリダイレクトされません。 (実際にはservers.txt最初の繰り返しの前にファイルの内容全体をメモリに読み込みます。)したがって、ssh端末から標準入力を読み続けます(またはスクリプトの呼び出し方法によっては何も読み取らない場合があります)。

解決策

少なくともbashでは、read他のファイル記述子を使用できます。

while read -u10 HOST ; do ssh $HOST "uname -a" ; done 10< servers.txt
#          ^^^^                                       ^^

動作する必要があります。10私が選択したファイル番号だけが必要です。 0、1、2は定義された意味を持ち、通常はファイルを開くことができる最初の数字で始まります(したがって、3は次に使用されます)。したがって、10は邪魔にならないほど高いですが、一部の砲弾の限界より低いほど低いです。さらに、それは良い丸い数字です...

代替ソリューション 1: -n

〜のようにマクニスで指摘する彼/彼女の答え、OpenSSHクライアントには-n標準入力を読み取らないようにするオプションがあります。これは特定のケースではうまく機能しますsshが、もちろん他のコマンドではこれが不足する可能性があります。他の解決策は、どのコマンドが標準入力を使用しているかに関係なく動作します。

代替ソリューション2:2番目のリダイレクト

明らかに、次のように2番目のリダイレクトを実行できます(たとえば、試してみたが、少なくとも私のBashバージョンでは動作しました...)。

while read HOST ; do ssh $HOST "uname -a" < /dev/null; done < servers.txt

どのコマンドにも使用できますが、実際に端末入力をコマンドに含めたい場合は困難です。

おすすめ記事