Bash:循环存储的主机名,通过 SSH 在这些主机上执行命令

Dav*_*ave 1 ssh cygwin bash openssh bash-scripting

我将主机名列表存储在名为 ssh_hosts.txt 的文件中。在 shell 脚本中,我循环访问 ssh_hosts.txt 中的主机名,并通过 SSH 在指定主机上执行命令。shell 脚本如下所示。

问题是脚本在处理第一个主机后退出。但是,如果我除了通过 ssh 在指定主机上执行命令之外执行其他操作,脚本将运行完成。

在下面的示例中,我注释掉了对 ssh 的调用,并将其替换为当前主机名的简单回显。这将运行直至完成。

我从 Windows 7 上的以下 Cygwin 版本下运行的 bash shell 执行此脚本:

$ uname -a
CYGWIN_NT-6.1 myHostname 1.7.16(0.262/5/3) 2012-07-20 22:55 i686 Cygwin
Run Code Online (Sandbox Code Playgroud)

涉及到的SSH版本有:

$ ssh -V
OpenSSH_6.0p1, OpenSSL 1.0.1c 10 May 2012

$ ssh myUsername@remoteHost 'ssh -V'
myUsername@remoteHost password:
OpenSSH_6.7p1 Debian-5+deb8u3, OpenSSL 1.0.1t  3 May 2016
Run Code Online (Sandbox Code Playgroud)

这是 shell 脚本:

#!/bin/bash

if [[ $# -ne 1 ]]; then
   echo "Usage: $(basename $0) <user name>"
   exit 1
fi

USER="$1"

while IFS='' read -r ssh_host || [[ -n "$ssh_host" ]];
do
   # This line will execute for all hosts listed in ssh_hosts.txt.
   echo $ssh_host

   # This line will execute for *only the first* host in ssh_hosts.txt.
   # ssh $USER@$ssh_host 'echo $(whoami)@$(hostname)'
done < ssh_hosts.txt
Run Code Online (Sandbox Code Playgroud)

如何让这个 shell 脚本在 ssh_hosts.txt 中的所有主机上执行,而不仅仅是在第一个主机上执行?

vir*_*tex 5

您的循环中有两个程序都从 stdin 读取:read 和 ssh。当循环运行时,读取命令将从 ssh_hosts.txt 读取第一行,然后 ssh 读取其余内容。这就是为什么您只看到它连接到第一个主机。

我知道这个问题有两种解决方案。一种是重写循环,使其不会从标准输入重定向。做到这一点的一个好方法是使用forEggo 在他的帖子中的循环。

另一个解决方案是将-n选项传递给ssh

ssh -n $USER@$ssh_host 'echo $(whoami)@$(hostname)'
Run Code Online (Sandbox Code Playgroud)

这告诉 ssh 不要使用 stdin,将 ssh_hosts.txt 的完整内容留给 read 命令。此解决方案要求您的 ssh 会话不需要与用户进行任何交互,包括提示输入密码(因此使用 ssh 密钥进行身份验证)。