Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
940 views
in Technique[技术] by (71.8m points)

shell - 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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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
' "$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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...