简体   繁体   中英

Execute a command on remote hosts via ssh from inside a bash script

I wrote a bash script which is supposed to read usernames and IP addresses from a file and execute a command on them via ssh.

This is hosts.txt :

user1 192.168.56.232
user2 192.168.56.233

This is myScript.sh :

cmd="ls -l"

while read line
do
   set $line
   echo "HOST:" $1@$2
   ssh $1@$2 $cmd
   exitStatus=$?
   echo "Exit Status: " $exitStatus
done < hosts.txt

The problem is that execution seems to stop after the first host is done. This is the output:

$ ./myScript.sh
HOST: user1@192.168.56.232
total 2748
drwxr-xr-x 2 user1 user1    4096 2011-11-15 20:01 Desktop
drwxr-xr-x 2 user1 user1    4096 2011-11-10 20:37 Documents
...
drwxr-xr-x 2 user1 user1    4096 2011-11-10 20:37 Videos
Exit Status:  0
$

Why does is behave like this, and how can i fix it?

In your script, the ssh job gets the same stdin as the read line , and in your case happens to eat up all the lines on the first invocation. So read line only gets to see the very first line of the input.

Solution: Close stdin for ssh , or better redirect from /dev/null . (Some programs don't like having stdin closed)

while read line
do
    ssh server somecommand </dev/null    # Redirect stdin from /dev/null
                                         # for ssh command
                                         # (Does not affect the other commands)
    printf '%s\n' "$line"
done < hosts.txt

If you don't want to redirect from /dev/null for every single job inside the loop, you can also try one of these:

while read line
do
  {
    commands...
  } </dev/null                           # Redirect stdin from /dev/null for all
                                         # commands inside the braces
done < hosts.txt


# In the following, let's not override the original stdin. Open hosts.txt on fd3
# instead

while read line <&3   # execute read command with fd0 (stdin) backed up from fd3
do
    commands...       # inside, you still have the original stdin
                      # (maybe the terminal) from outside, which can be practical.

done 3< hosts.txt     # make hosts.txt available as fd3 for all commands in the
                      # loop (so fd0 (stdin) will be unaffected)


# totally safe way: close fd3 for all inner commands at once

while read line <&3
do
  {
    commands...
  } 3<&-
done 3< hosts.txt

The problem that you are having is that the SSH process is consuming all of the stdin, so read doesn't see any of the input after the first ssh command has ran. You can use the -n flag for SSH to prevent this from happening, or you can redirect /dev/null to the stdin of the ssh command.

See the following for more information: http://mywiki.wooledge.org/BashFAQ/089

确保使用ssh -n不从hosts.txt读取ssh命令

I have a feeling your question is unnecessarily verbose..

Essentially you should be able to reproduce the problem with:

while read line
do
   echo $line
done < hosts.txt

Which should work just fine.. Do you edit the right file? Are there special characters in it? Check it with a proper editor (eg: vim).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM