Bash脚本并行SSH远程命令

9

我有一个脚本,通过ssh连接在几台不同的机器上执行远程命令。 脚本大致如下:

for server in list; do
echo "output from $server"
ssh to server execute some command
done

这个问题显然在于时间,因为它需要建立ssh连接、发送命令、等待回复并打印。我希望有一个脚本可以尝试一次性建立所有连接,并在接收到输出和命令输出后返回echo“$server的输出”,所以不必按列表顺序。
我已经搜索了一段时间,但没有找到答案。如其他帖子中所建议的单线程运行命令后无法取消ssh会话,因为我需要输出,而且不能使用其他工具,只能使用GNU Bash,版本为4.1.2(1)-release。
另一个问题是像这样的ssh会话如何限制?如果我简单地粘贴5行或更多的“ssh连接,执行命令”的命令行,它实际上什么都不做,或者只在列表中的第一条执行。(如果我粘贴3-4行,则可以正常工作)。谢谢。

在尝试编写脚本之前,想象一下您希望通过交互式工作(例如,通过在终端中键入命令)实现以上目标的方式。 - clt60
4个回答

9

你试过这个吗?

for server in list; do
  ssh user@server "command" &
done
wait
echo finished

更新: 开始子 shell:

for server in list; do
  (echo "output from $server"; ssh user@server "command"; echo End $server) &
done
wait
echo All subshells finished

1
谢谢您的回答,是的,我尝试了类似的方法,但输出结果并不令人满意,因为我需要行“echo“output from $server””,这样我就知道输出来自哪个服务器。 如果我添加echo行,我将得到所有的echo,然后是所有的输出,这样会很混乱。我需要它按照“echo“output from $server””输出,然后是另一个。 - user3338991
基本上,问题是如何在与ssh user@server "command" &相同的“级别”上获取行回显“output from $server”,这样我就可以同时获得这些输出。 - user3338991

4
有几个可以处理此类任务的并行SSH工具: 另外,您可能会对配置部署解决方案感兴趣,例如Chef,Puppet,Ansible,Fabric等(请参见此摘要)。
第三种选择是使用终端广播,例如pconsole
如果您只能使用GNU命令,则可以像这样编写脚本:
for server in $servers ; do
   ( { echo "output from $server" ; ssh user@$server "command" ; } | \
    sed -e "s/^/$server:/" ) & 
done
wait 

然后将输出进行排序,以协调行。

谢谢您的回答,不幸的是我不能使用除GNU bash版本4.1.2(1)-release之外的任何其他工具。(抱歉忘记提到了) - user3338991
@user3338991:最后一部分是你需要的:它会在每行开头添加哪个服务器打印了该行。但它需要修复以便也能为stderr添加前缀:for server in $servers ; do ( ssh user@$server "command 2>&1" 2>&1 | sed -e "s/^/from $server: /" ) & ; done ; wait - Olivier Dulac

4
我从本帖中提到的shell hacks开始,然后转向了更加稳健的东西:https://github.com/bearstech/pussh 这是我的日常工作马车,我基本上可以在20秒内对250个服务器运行任何东西(否则连接速率会杀死我的ssh-agent)。我已经使用了多年。
请从手册页中查看自己(克隆它并运行'man ./pussh.1'):https://github.com/bearstech/pussh/blob/master/pussh.1 例子 按降序显示所有服务器的rootfs使用情况:
pussh -f servers df -h / |grep /dev |sort -rn -k5

计算集群中处理器的数量:

pussh -f servers grep ^processor /proc/cpuinfo |wc -l

按出现次数排序显示处理器型号:

pussh -f servers sed -ne "s/^model name.*: //p" /proc/cpuinfo |sort |uniq -c

获取每个主机上已安装软件包的列表,并将其保存在一个文件中:

pussh -f servers -o packages-for-%h dpkg --get-selections

批量复制文件树(广播):

tar czf files.tar.gz ... && pussh -f servers -i files.tar.gz tar -xzC /to/dest

批量复制多个远程文件树(收集):

pussh -f servers -o '|(mkdir -p %h && tar -xzC %h)' tar -czC /src/path .

请注意,pussh -u功能(上传并执行)是我编写此程序的主要原因,似乎没有其他工具能够做到这一点。我仍然想知道今天是否还是如此。

今天真希望有一个线程限制器......同样重要的是,远程命令返回错误处理。 - keen

3

您可能会喜欢使用 parallel-ssh 项目 中的 pssh 命令:

pssh -h servers.txt -l user command

当命令成功执行时,每个服务器都将输出一行。通过使用-P选项,您还可以查看命令的输出。


1
谢谢您的回答,不幸的是我不能使用除GNU bash版本4.1.2(1)-release之外的任何其他工具。(抱歉忘记提到了) - user3338991

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