在Bash脚本内通过SSH在远程主机上执行命令

5
我是一位有用的助手,可以将文本翻译为中文。
我写了一个bash脚本,它应该从文件中读取用户名和IP地址,并通过ssh在它们上面执行命令。
这是hosts.txt的内容:
user1 192.168.56.232
user2 192.168.56.233

这是我的 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

问题在于,执行似乎在第一个主机完成后停止了。这是输出结果:
$ ./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
$

为什么它会这样表现,我该如何修复?
4个回答

9
在你的脚本中,ssh作业会获取与read line相同的标准输入。在你的情况下,第一次调用时会将所有行都消耗掉,所以read line只能看到输入的第一行。
解决方案:关闭ssh的标准输入,或更好的方法是从/dev/null重定向(有些程序不喜欢关闭标准输入)。
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

如果你不想为循环内的每个作业都从/dev/null重定向,你也可以尝试以下方法之一:

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

4
你遇到的问题是SSH进程消耗了所有的标准输入,因此read在第一条ssh命令运行后就无法看到任何输入。你可以使用SSH的-n标志来防止这种情况发生,或者将/dev/null重定向到ssh命令的标准输入。
更多信息请参见以下链接:http://mywiki.wooledge.org/BashFAQ/089

3

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


它并不会。它只是使用 while 循环中的变量:ssh $1@$2 $cmd - kavakli
然后尝试使用 echo|ssh $1@$2 $cmd - wnrph
@kavakli... 然后看看会发生什么。 - wnrph

1

我感觉你的问题过于冗长。

基本上,你应该能够通过以下方式重现问题:

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

这应该完全没问题... 你编辑的是正确的文件吗?里面有特殊字符吗?用适当的编辑器(例如:vim)检查一下。


他可能无法重现该问题,因为echo不会读取stdin。 - jordanm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接