bashスクリプトを使用して、テキストファイルを読み取り、各行で何かを実行しようとしています。
だから、私はこのようなリストを持っています:
server1
server2
server3
server4
次のように、whileループを使用してこれをループできると思いました:
while read server; do
ssh $server "uname -a"
done < /home/kenny/list_of_servers.txt
whileループは、1回実行すると停止するため、uname -a
のみを実行します。 server1で
ただし、catを使用したforループでは、正常に機能します:
for server in $(cat /home/kenny/list_of_servers.txt) ; do
ssh $server "uname -a"
done
私にとってさらに困惑するのは、これも機能することです。
while read server; do
echo $server
done < /home/kenny/list_of_servers.txt
最初の例が最初の反復後に停止するのはなぜですか?
承認された回答:
for
ここではループは問題ありません。ただし、これはファイルにマシン名が含まれているためであることに注意してください。マシン名には空白文字やグロブ文字が含まれていません。 for x in $(cat file); do …
file
の行を反復処理することはできません 一般に、シェルは最初にコマンドcat file
からの出力を分割するためです。 空白がある場所ならどこでも、各単語をグロブパターンとして扱うので、\[?*
さらに拡張されます。 $(catファイル)でxのfor x in $(cat file)
作業すれば安全です:
set -f
IFS='
'
for x in $(cat file); do …
関連資料:名前にスペースが含まれるファイルをループする?; bashの変数から1行ずつ読み取るにはどうすればよいですか?; while IFS= read
はなぜですか? IFS=; while read..
?読み取り中にwhile read
に注意してください 、行を読み取るための安全な構文はwhile IFS= read -r line; do …
。
それでは、while read
の問題点に目を向けましょう。 試み。サーバーリストファイルからのリダイレクトは、ループ全体に適用されます。したがって、ssh
実行すると、その標準入力はそのファイルから取得されます。 sshクライアントは、リモートアプリケーションが標準入力からいつ読み取りたいかを知ることができません。したがって、sshクライアントは入力に気付くとすぐに、その入力をリモート側に送信します。そこにあるsshサーバーは、必要に応じて、その入力をリモートコマンドに送る準備ができています。あなたの場合、リモートコマンドが入力を読み取ることはないため、データは破棄されてしまいますが、クライアント側はそれについて何も知りません。 echo
でのあなたの試み echo
のために機能しました 入力を読み取ることはなく、標準の入力をそのままにします。
これを回避する方法はいくつかあります。 -n
を使用して、標準入力から読み取らないようにsshに指示できます。 オプション。
while read server; do
ssh -n $server "uname -a"
done < /home/kenny/list_of_servers.txt
-n
オプションは実際にはssh
に指示します 入力を/dev/null
からリダイレクトします 。これはシェルレベルで実行でき、どのコマンドでも機能します。
while read server; do
ssh $server "uname -a" </dev/null
done < /home/kenny/list_of_servers.txt
ファイルからのsshの入力を回避するための魅力的な方法は、read
にリダイレクトを配置することです。 コマンド:while read server </home/kenny/list_of_servers.txt; do …
。 read
のたびにファイルが再度開かれるため、これは機能しません。 コマンドが実行されます(ファイルの最初の行を何度も読み取るため)。ファイルがループの期間中に1回開かれるように、リダイレクトは全体としてwhileループである必要があります。
一般的な解決策は、標準入力以外のファイル記述子でループへの入力を提供することです。シェルには、ある記述子番号から別の記述子番号に入力と出力を渡すための構造があります。ここでは、ファイル記述子3でファイルを開き、read
をリダイレクトします。 ファイル記述子3からのコマンドの標準入力。sshクライアントは開いている非標準記述子を無視するため、すべて問題ありません。
while read server <&3; do
ssh $server "uname -a"
done 3</home/kenny/list_of_servers.txt
bashでは、read
コマンドには、別のファイル記述子から読み取るための特定のオプションがあるため、read -u3 server
と書くことができます。 。
関連資料:ファイル記述子とシェルスクリプト;追加のファイル記述子をいつ使用しますか?