运行 在多台服务器上通过 ssh 执行顺序命令

Running sequential commands through ssh on multiple servers

我在传递给以下脚本的文件中有一个服务器列表:

#!/bin/bash

while IFS='' read -r line || [[ -n "$line" ]]; do

    ssh_cmd="user@$line"
    ssh $ssh_cmd 'hostname && ls -l /path/to/folder | grep some_token' &

done < ""

我想要的是这样的输出:

  output from hostname (1)
  output from ls -l (1)
  output from hostname (2)
  output from ls -l (2)
  output from hostname (3)
  output from ls -l (3)

但是这些好像混在一起了:

  output from ls -l (1)
  output from hostname (1)      
  output from hostname (2)
  output from ls -l (2)
  output from ls -l (3)
  output from hostname (3)

有什么方法可以确保这些命令按顺序执行吗?

在此致谢!

此行末尾的 & 使进程在后台运行:

ssh $ssh_cmd 'hostname && ls -l /path/to/folder | grep some_token' &

如果您从该行中删除 &,脚本将等到 ssh 会话完成以继续循环的下一次迭代。此外,您需要将 -n 标志添加到 ssh 命令,这样它就不会从标准输入中读取。这将为您提供所需的顺序输出。

最终命令:

ssh -n $ssh_cmd 'hostname && ls -l /path/to/folder | grep some_token'

使用 GNU Parallel 并行处理它们并使用 -k 选项保持输出顺序:

parallel -k -a hosts.txt 'echo ssh user@{} "hostname; ls"'

因此,如果 hosts.txt 包含以下内容:

host1
host27
host32
host100
hostfreddyfrog
hostmichaelfish

你会得到这个:

ssh user@host1 hostname; ls
ssh user@host27 hostname; ls
ssh user@host32 hostname; ls
ssh user@host100 hostname; ls
ssh user@hostfreddyfrog hostname; ls
ssh user@hostmichaelfish hostname; ls

很明显,您需要删除 echo 并添加您的引用和抓取,但概念应该足够清楚。

另一个优点,除了它现在是单行的,如果你有 32,000 台主机要工作,GNU Parallel 可以使用 -j 标志告诉,有多少个进程一次 运行 而不会使您的服务器超载。默认情况下,如果您的 CPU 中有 8 个内核,它将并行 运行 8 个作业,但您可以将其设置为 64,例如

parallel -k -j 64 ...

您还可以设置 GNU Parallel 以便能够 ssh 进入主机本身,通常是为了在服务器之间分配处理作业,这样作业就变得更加容易了。

parallel -S node1,node4,node56 'hostname; grep ...'

example here.

传递 hosts.txt 的替代语法是

parallel -k 'echo ssh user@{} "hostname; ls"' < hosts.txt

parallel -k 'echo ssh user@{} "hostname; ls"' :::: hosts.txt