web-dev-qa-db-ja.com

読み取りループが早く壊れている間にbash

私はこれでしばらくの間壁に頭をぶつけてきました。

一連のマシンにSSHで接続し、それらが使用可能かどうかを確認したい(接続を受け入れて使用されていない)。私は小さなスクリプトtsshを作成しました。これは、まさにそれを実行します。

#!/bin/bash

Host=$1
timeout=${2:-1}

ssh -qo "ConnectTimeout $timeout" $Host "[ \`who | cut -f1 | wc -l \` -eq 0 ] && exit 0 || exit 1"

このスクリプトは正しく機能します。接続に問題があった場合は255を返し、マシンがビジーの場合は1を返し、すべてが正常な場合は0を返します。誰かがこれを行うためのより良い方法を知っているなら、私に知らせてください。

そこで次に、while読み取りループを使用してマシンのセットでtsshを呼び出そうとしますが、これですべてがうまくいきません。 tsshが0を返すとすぐにループが終了し、フルセットが完了することはありません。

while read nu ; do tssh "MYBOXES$nu" ; done < <(Ruby -e '(0..20).each { |i| puts i }')

最初はこれはサブシェルの問題だと思いましたが、明らかにそうではありませんでした。スタイル/コンテンツに関するコメントと一緒に、どんな助けでも大歓迎です!理由がわかったら自分を蹴るつもりだとわかっている...

28
wopwop

それが役立つかどうかはわかりませんが、よりクリーンな書き方は

for nu in `Ruby -e '(0..20).each { |i| puts i}'`; do
  tssh "MYBOXES$nu" 
done
4
Paul Tomblin

クリスは正しいです。ループブレークの原因はstdinを使用したSSHでしたが、ループ方法の使用法は正しいです。

入力(たとえば、ホスト名のリストを含むファイル)をループし、SSHを呼び出す場合は、-nパラメーターを渡す必要があります。そうしないと、入力に基づくループが失敗します。

while read Host; do
  ssh -n $Host "remote command" >> output.txt
done << Host_list_file.txt
41
user170405

構成内

something | 
while read x; do 
    ssh ...
done

whileループで見られる標準入力は、somethingの出力です。

sshのデフォルトの動作は、標準入力を読み取ることです。これにより、次のようなことができます

cat id_rsa.pub | ssh new_box "cat - >> ~/.ssh/authorized_keys"

そうは言っても、最初の値が読み取られると、最初のsshコマンドはsomethingから入力全体を読み取ります。その後、sshが終了するまでに出力がなくなり、readが停止します。

修正はssh -n ...例:.

cat /etc/hosts | awk '{print $2}' | while read x; do
    ssh -n $x "do_something_on_the_machine"
done
34
Foo Bah

私は今日これに遭遇しました-rshおよび/またはsshは、stdinを使用しているため、while読み取りループを中断する可能性があります。 ssh行に-nを挿入して、stdinの使用を停止し、問題を修正しました。

7
Chris Warren

答えのほとんどはsshに固有のものです。他のコマンドもstdinをハイジャックし、-nオプションはありません。これは他のコマンドに対処する必要があります。これはsshでも機能するはずです。

while read x; do 
    # Make sure command does not Hijack stdin
    echo "" | command $x
done < /path/to/some/file
6
rouble

なぜ失敗するのかもわかりませんが、xargsseqが好きです。

seq 0 20 | xargs -n1 tssh MYBOXES

Kaiiが述べたように、数値の範囲を出力するためだけにRubyまたはseq(BSDまたはOSXマシンでは機能しません)を呼び出すのは本当にやり過ぎです。bashの使用に満足している場合はできる:

for i in {0..20}; do
    # command
done

これはbash2.05b以降で機能するはずです。

3
guns

「ピーターを奪ってポールに支払う」問題について話します。読み取りループ中にsshが何かを殺していた理由を理解するのに何時間も苦労していました。

While読み取りループを維持し、同時にsshを維持する別の方法は、「-n」スイッチを使用してssh/dev/nullでSTDINを作成することです。私にとって魅力のように機能します:

#!/bin/bash
[...]
something|while read Host
   do
      ssh -nx ${Host} fiddleAround
   done

(トンネル内でXをネゴシエートする時間を無駄にしないために、私は常に「-x」も使用する傾向があります。)

2
Kevin Mullet

ループが壊れたのは0の結果だとは信じられません。ループ内のtsshコマンドを「/ bin/true」に置き換えることでこれをテストできます。これも0を返します。

スタイルに関しては、単純なループシェルスクリプトにRuby、Perl、seq、jot、または* BSDにないその他のバイナリが必要な理由がわかりません。

あるいは、少なくともksh、bashで機能するforループ構造に組み込まれたシェルを使用することもできます。

for ((i=0; $i<=20; i++)); do
    tssh "MYBOXES$i"
done
2
Kaii