Difference between WHILE and FOR loops

This might be a simple question, but I can't find the answer out there anywhere. I'm trying to write a loop to SSH to a server for me to then copy/paste some commands in. Once I'm done, I type 'exit' and the loop should then automatically SSH to the next server in line.

The 'dbs_group' file contains 5 hostnames, one per line. Nothing else.

Seems to work fine in a FOR loop, but not in a WHILE loop.

For example (server names replaced with 'xxx'):

[chris@x] for HOST in $(cat dbs_group); do ssh $HOST; done
Last login: Thu Apr 23 10:08:51 2015 from xxx.com
[chris@xxx1] exit
logout
Connection to xxx1 closed.
Last login: Sat Apr 18 13:56:28 2015 from xxx.com
[chris@xxx2] exit
logout
Connection to xxx2 closed.

etc., which is what I was expecting.

But using a WHILE loop:

[chris@x] cat dbs_group | while read HOST; do ssh $HOST; done
Pseudo-terminal will not be allocated because stdin is not a terminal.
-bash: line 1: xxx1: command not found
-bash: line 2: xxx2: command not found
-bash: line 3: xxx3: command not found
-bash: line 4: xxx4: command not found
-bash: line 5: xxx5: command not found
[chris@x] 

I understand that the error above might be resolved by using 'ssh -t -t' but I'm just trying to figure out why the two different loops respond differently. I thought both of them would process the dbs_group file line per line and assign the variable to HOST.

Thanks,

Chris

Hi,
The '|' use a subshell ( without pseudo-terminal. )
A "while" approach as your "for" loop:

while read HOST; do ssh $HOST; done <dbs_group

Regards.

Hi disedorgue,

I still get the same when using that method:

[chris@x] while read HOST; do ssh $HOST; done <dbs_group
Pseudo-terminal will not be allocated because stdin is not a terminal.
-bash: line 1: xxx1: command not found
-bash: line 2: xxx2: command not found
-bash: line 3: xxx3: command not found
-bash: line 4: xxx4: command not found
-bash: line 5: xxx5: command not found
[chris@x] 

Cheers,

Chris

Try:

while read HOST <&3; do ssh $HOST; done 3<dbs_group
2 Likes

Thanks Scrutinizer, that's done the trick.

So why the difference? Do the two loops process the file differently?

Cheers,

Chris

You're welcome. Yes, the for loop does not redirect stdin, whereas the while read loop does. stdin is needed by the ssh command, so ssh was complaining that stdin could not be used..
The adaptation uses the unused file descriptor 3 rather than stdin (file descriptor 0)..

3 Likes

or alternatively:

while read HOST; do ssh $HOST </dev/null; done <dbs_group