GNU/Linux >> Linux の 問題 >  >> Linux

Bashを使用してファイルから行を読み取る:対その間?

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ループである必要があります。

関連:BashScriptはターミナルからは機能しますが、CronTabからは機能しませんか?

一般的な解決策は、標準入力以外のファイル記述子でループへの入力を提供することです。シェルには、ある記述子番号から別の記述子番号に入力と出力を渡すための構造があります。ここでは、ファイル記述子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と書くことができます。 。

関連資料:ファイル記述子とシェルスクリプト;追加のファイル記述子をいつ使用しますか?


Linux
  1. 「.bashrc」と同等のファイルがすべてのシェルによって読み取られますか?

  2. 指定された行数で/dev/ urandomからのストリームでファイルを埋める方法は?

  3. 別の行からのAWK?

  1. ファイルからGrepパターンを読み取る?

  2. アセンブリ内のファイルからの読み取り

  3. LinuxシェルからのSQLクエリを含むCSVファイルの読み取り

  1. Linux用の10個の便利なBashエイリアス

  2. Bash の For ループと While ループの例

  3. BASH で mv を使用してファイル名にタイムスタンプを追加する