Shell-scripting: A loop is a loop, or is it not?

When tasked to do things multiple time, you usually don’t type things multiple times or copy/paste them. Instead, you write a loop which does that for you. Yesterday, I horribly tumbled trying to use one of those loops.

I had to change the content of a file on numerous machines. So I wrote the machine names into a file and ran

cat hosts | while read h; do ssh $h "sed -i 's/a/b/g' file"; done

I considered that “more elegant” than a bulky line as in “for h in host1 host2 host3 … host251; do” …

Well, since the loop did not present any error messages, I considered the task done. Couple hours later though, I notice the change I made apparently did not work and so investigated what happened. Turns out, only the first host in my “hosts” file was changed. Huh?!

I quickly tested the behaviour by running a test loop like

cat hosts | while read h; do ssh $h "hostname"; done

Which only gave one hostname. Using a for-loop however, worked.

for h in $(cat hosts); do ssh $h "hostname"; done

A colleague suggested using the “-n” switch for the ssh command and this apparently fixed the “issue”. Running that “while read”-loop with “ssh -n” again fixed the file on all hosts. The reason for this behaviour is interesting though. ssh, by default, “grabs” the stdin file descriptor and prevents “read” to use it after having read the first argument. The -n switch tells ssh to use /dev/null as stdin instead which makes the loop work as expected. In the for-loop however, there is no problem with ssh grabbing stdin because the loop iterations are not read from there.



3 responses to “Shell-scripting: A loop is a loop, or is it not?

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s