BLOGTIMES
2009/03/14

sshを使うとbashのループが回らない?

  cli  sh  ssh 
このエントリーをはてなブックマークに追加

sshを使って他のホストのコマンド呼び出しを行うシェルスクリプトを開発していたのですが、自分が意図する動作にならずに色々と試行錯誤をする羽目になったので、同じところではまらないようにメモを残しておきます。

#!/bin/bash seq 1 5 | while read i ; do echo $i ssh host1.example.com 'hostname' done

今回書いたのは上記のようなスクリプトでhost1.example.com上でhostnameコマンドを実行するというのをループで5回繰り返すものです。

$ ./example.sh 1 host1.example.com

一見何の問題もないように見えるのですが、実際に実行してみると上記のようにループが1回しか実行されず、意図通りに動作しません。初めはループの書き方が悪いのかと思って色々と試行錯誤していたのですが、不思議なことにsshの行をコメントアウトするとループは最後まで回るようになることに気づきました。ループの継続判定はreadがstdinを読み込めるかどうかによって行われているので、ここから導かれる原因はsshによってstdinが自分の意図しないところで読み捨てられているということになります。

解決方法は -n オプション

ということで、sshのmanを調べてみると今回の件におあつらえむきの-nオプションというのもがありました。

man 1 ssh

-n

Redirects stdin from /dev/null (actually, prevents reading from stdin). This must be used when ssh is run in the background. A common trick is to use this to run X11 programs on a remote machine. For example, ssh -n shadows.cs.hut.fi emacs & will start an emacs on shadows.cs.hut.fi, and the X11 connection will be automatically forwarded over an encrypted channel. The ssh program will be put in the background. (This does not work if ssh needs to ask for a password or passphrase; see also the -f option.)

これまであまり意識していませんでしたが、考えてみればsshはリモートとstdin/stdoutの内容をやりとりしているので、今回のように明確にstdinが読み取られたくない場合にはオプションをつけないといけないというのは合理的なわけですね。

ということで、スクリプトに下記のように-nオプションを追加したら意図通り動くようになりました。

#!/bin/bash seq 1 5 | while read i ; do echo $i ssh host1.example.com -n 'hostname' done
$ ./example.sh 1 host1.example.com 2 host1.example.com 3 host1.example.com 4 host1.example.com 5 host1.example.com

    トラックバックについて
    Trackback URL:
    お気軽にどうぞ。トラックバック前にポリシーをお読みください。[policy]
    このエントリへのTrackbackにはこのURLが必要です→https://blog.cles.jp/item/2964
    Trackbacks
    このエントリにトラックバックはありません
    Comments
    愛のあるツッコミをお気軽にどうぞ。[policy]
    古いエントリについてはコメント制御しているため、即時に反映されないことがあります。
    コメントはありません
    Comments Form

    コメントは承認後の表示となります。
    OpenIDでログインすると、即時に公開されます。

    OpenID を使ってログインすることができます。

    Identity URL: Yahoo! JAPAN IDでログイン