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
どのコマンドにも使用できますが、実際に端末入力をコマンドに含めたい場合は困難です。
答え2
ssh
DeRobertが説明したようにstdin
。
この動作を変更するには、-n no ssh を追加して標準入力を読み取らないようにすることができます。
ssh -n $HOST "uname -a"
答え3
実際に使用する方が良いでしょう。パフパフ~からパラレルSSHプロジェクト。
pssh -h $hostfile -t $timeout -i $commands
-i
相互作用を意味します。 psshには並列scpと並列rsyncも付属しています。利点は、非同期で実行され、必要なだけスレッドを実行できることです。デフォルト(非i / interactive)は、$ outputdir / $ hostnameを介して実行されるstdout / stderrの別のディレクトリに出力することです。
答え4
sshコマンドはwhileステートメントによって提供される標準入力からすべてのストリームを取得するため
パイプを使用して、SSHの標準入力を別のソースに切り替えることができます。
echo "" | ssh ...
例:
while read HOST ; do echo "" | ssh $HOST "uname -a" ; done < servers.txt
whileループ内のすべてのsshコマンドのstdin入力を別のソースに切り替える必要があります。