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

时间:2015-08-05 03:30:52

标签: bash unix ssh

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

#!/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 < "$1"

我想要的是这样输出:

  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)

有没有办法确保这些命令按顺序发生?

先谢谢!

2 个答案:

答案 0 :(得分:1)

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

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

如果从该行中删除&,脚本将等到ssh会话结束后继续循环的下一次迭代。此外,您需要将-n标志添加到ssh命令,以便它不从stdin读取。这将为您提供您正在寻找的顺序输出。

最终命令:

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

答案 1 :(得分:0)

使用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