SSHによりwhileループが停止します


30

私はついに数週間苦労してきた問題を解決することができました。リモートでコマンドを実行するために、「承認されたキー」でSSHを使用します。whileループで実行する場合を除き、すべて問題ありません。ループは、sshコマンドでの反復を完了すると終了します。

長い間、これはある種のkshの奇妙さだと思っていましたが、bashが実際に同じように動作することを発見しました。

問題を再現する小さなサンプルプログラム。これは、スナップショットを取得し、クラスター内のノード間でスナップショットを複製する大規模な実装から抽出されます。

#!/bin/bash

set -x

IDTAG=".*zone"
MARKER="mark-$(date +%Y.%m.%d.%H.%M.%S)"
REMOTE_HOST=sol10-target
ZFSPARENT=rpool

ssh $REMOTE_HOST zfs list -t filesystem -rHo name,mounted $ZFSPARENT | grep "/$IDTAG    " > /tmp/actionlist

#for RMT_FILESYSTEM in $(cat /tmp/actionlist)
cat /tmp/actionlist | while read RMT_FILESYSTEM ISMOUNTED
do
   echo ${RMT_FILESYSTEM}@${MARKER}
   [ "$ISMOUNTED" = "yes" ] && ssh $REMOTE_HOST zfs snapshot -r ${RMT_FILESYSTEM}@${MARKER}
   echo Remote Command Return Code: $?
done

(zfsリストの「-H」オプションの動作の定義に従って、grep検索式にTAB文字があることに注意してください。)

私のサンプルには、ルートにいくつかのZFSファイルシステムがあり、すべての「ゾーン」が、次のような名前のデータセットにルートファイルシステムを持っています。

POOL / zones / app1zone
POOL / zones / group2 / app2zone

上記のループは、選択した各データセットのスナップショットを作成する必要がありますが、代わりに最初のループでのみ動作し、終了します。

プログラムが適切な数のデータセットを見つけたことは、スクリプトが存在した後に「/ tmp / actionlist」ファイルをチェックすることで簡単に確認できます。

sshコマンドがたとえばechoコマンドに置き換えられた場合、ループはすべての入力行を反復処理します。または私のお気に入り-問題のコマンドに「エコー」を追加します。

代わりにforループを使用した場合も機能しますが、データセットのリストの潜在的なサイズのために、コマンドラインの最大長に問題が生じる可能性があります。

私は、99.999%で、sshコマンドを含むループのみが問題を引き起こすと確信しています。

sshコマンドが実行される反復が完了することに注意してください!whileループに入力されたデータが突然失われるかのように...最初のいくつかの入力行がsshコマンドを実行しない場合、ループは実際にSSHコマンドを実行するまで続きます。

これをテストしている私のラップトップには、2つまたは3つのサンプルデータセットのみを含む2つのSolaris 10 VMがありますが、これは、これが稼働する予定の大規模なSPARCシステムでも発生しており、多くのデータセットがあります。


7
SSHは標準入力から読み取って、あなたのactionlist。sshの標準入力を/dev/null
BatchyX

やってみます。ラッパーにsshを入れても役に立たないことを付け加えたいと思います。--
ヨハン

あなたは正しいです。どうしてそれが見えなかったの!?
ヨハン

@BatchyXあなたのコメントは答えとしての資格があると思います。
CVn

@BatchyXがそのようにそれを再投稿できれば、答えを「受け入れる」ことに同意します。
ヨハン

回答:


43

SSHが標準入力から読み取って、アクションリストを使い果たしている可能性があります。sshの標準入力を/ dev / nullにリダイレクトしてみてください:

ssh $REMOTE_HOST zfs snapshot -r ${RMT_FILESYSTEM}@${MARKER} </dev/null

一般的なルールとして、while read-styleループの下で標準入力に干渉する可能性のあるコマンドを実行する場合、ループ全体を中括弧で囲むのが好きです。

cat /tmp/uuoc | while read RMT_FILESYSTEM ISMOUNTED
do {
    echo ${RMT_FILESYSTEM}@${MARKER}
    [ "$ISMOUNTED" = "yes" ] && ssh $REMOTE_HOST zfs snapshot -r ${RMT_FILESYSTEM}@${MARKER}
    echo Remote Command Return Code: $?
} < /dev/null; done

3
まず最初に、中括弧の特定の使用について素晴らしいです... 20年間スクリプトに出会ったことがありません(少なくとも覚えていることはありません)。そしてuuoc推論について。FWIW(および私自身の弁護において)読みやすくするために例外を作成し、冗長なcatステートメントを追加することがあります!私は突然新しいことを再び学んでいるので、このフォーラムが大好きです!具体的には、この場合のように行の先頭にリダイレクトを追加するのが好きですが、フォーラムでは問題を混乱させているようで、有用な応答が少なくなります!
ヨハン

{...}と(...)kshのマニュアルページでは、{...}はコマンドラインの先頭でのみ認識される特別なキーワードであるとの違いを解決しようとしています。しかし、別の違いがあります... ( </tmp/file [ -z "$SOMEVAR" ] && awk '{print "X", $0}' )中括弧と同じです。生成された出力という意味では、閉じ中括弧が新しい行にある必要があるという事実についてではありません
ヨハン

5
また、OpenSSHのsshには、-n/ dev / nullから標準入力を(事実上)再度開くオプションがあります。
クリスジョンセン

sudoループ内でコマンドを使用するための回避策はありますか?
ボン

私は...年代以来、-nを使用するために使用され、いくつかの点で習慣を失った....そして、私はそれをしなかった理由は、今私は再び知って、少し後に掘り過ごしながら
フロリアン・ハイグル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.