在 bash 脚本中通过 ssh 在远程主机上执行命令
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8376166/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Execute a command on remote hosts via ssh from inside a bash script
提问by kavakli
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.
我写了一个 bash 脚本,它应该从文件中读取用户名和 IP 地址,并通过 ssh 对它们执行命令。
This is hosts.txt :
这是 hosts.txt :
user1 192.168.56.232
user2 192.168.56.233
This is myScript.sh :
这是 myScript.sh :
cmd="ls -l"
while read line
do
set $line
echo "HOST:" @
ssh @ $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: [email protected]
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?
为什么会这样,我该如何解决?
回答by Jo So
In your script, the sshjob 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 lineonly gets to see
the very first line of the input.
在您的脚本中,ssh作业获得与 相同的标准输入read line,在您的情况下,在第一次调用时恰好吃光了所有行。所以read line只能看到输入的第一行。
Solution: Close stdin for ssh, or better redirect from /dev/null. (Some programs
don't like having stdin closed)
解决方案:关闭 stdin for 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
If you don't want to redirect from /dev/null for every single job inside the loop, you can also try one of these:
如果您不想为循环内的每个作业从 /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
回答by jordanm
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.
您遇到的问题是 SSH 进程正在消耗所有标准输入,因此在第一个 ssh 命令运行后 read 看不到任何输入。您可以使用 SSH 的 -n 标志来防止这种情况发生,或者您可以将 /dev/null 重定向到 ssh 命令的标准输入。
See the following for more information: http://mywiki.wooledge.org/BashFAQ/089
有关更多信息,请参阅以下内容:http: //mywiki.wooledge.org/BashFAQ/089
回答by artistoex
Make sure the sshcommand does not read from the hosts.txt using ssh -n
使用以下ssh命令确保该命令不会从 hosts.txt 中读取ssh -n
回答by Karoly Horvath
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).
哪个应该可以正常工作..您编辑正确的文件吗?里面有特殊字符吗?使用适当的编辑器(例如:vim)检查它。

