When SSH is used with a line like “while read ….”, the while loop will only run once.
This can be seen by running this simple example:
$ seq 1 10 | while read line; do ssh remotehostname "echo x${line}x"; done x1x
You might expect this to connect to the host with the name “remotehostname” 10 times, and each time print one of the numbers in the sequence from 1 to 10. This will, however, not be the case. The result is a single line, saying “1”.
Where did the rest of the numbers go? To the SSH process.
By default, SSH runs off with the stdin file descriptor, preventing “read” from reading anything else from it. You can see this by trying the following example:
$ seq 1 10 | while read line; do ssh remotehostname "echo x${line}x; cat -"; done x1x 2 3 4 5 6 7 8 9 10
Now all the numbers were printed, but they were all in a single ssh connection. As you can see, only the number “1” got the X’es on both sides, indicating it was printed by the “echo” instruction. The rest of the numbers come from “cat –“, which basically takes whatever comes in on SSH’s stdin, and dumps it to the stdout (the screen, in this case). So that’s where they went!
Now, how do you remedy this?
Answer: SSH’s -n switch. From the manual:
-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.)
So let’s try that with -n, shall we?
$ seq 1 10 | while read line; do ssh -n remotehostname "echo x${line}x; cat -"; done x1x x2x x3x x4x x5x x6x x7x x8x x9x x10x
There. 10 SSH connections opened, 1 number printed each time. A total waste of time, but a rather simple example to follow 🙂
6 Comments
Brilliantly described solution! I was racking my brains trying to work out why my loop kept exiting.
THANKS !
wow, even as a old school scripter, this feature always bothered me (I used </dev/null) but did not understand what's going on. Thanks.
brilliant! It was helpful a lot
It works!
Now my while loop does what I expected:
list_my_servers | while read s ; do echo $s ; ssh -n $s.avz.org.ua grep sql_mode /etc/my.cnf ; done
Thank you!
Whow !!!
I fighted days with that problem !!!