【问题标题】:Run ssh in shell script in parallel and set remote variables在 shell 脚本中并行运行 ssh 并设置远程变量
【发布时间】:2012-05-02 16:43:44
【问题描述】:

我正在编写一个脚本来读取输入文件,其中包含约 1000 行主机信息。脚本 ssh 到每个主机,cd 到远程主机日志目录并 cat latest 每日日志文件。然后我将 cat 日志文件重定向到本地,做一些模式匹配和统计。

我的程序的简化结构是一个while循环,如下所示:

while read host
do
    ssh -n name@$host "cd TO LOG DIR AND cat THE LATEST LOGFILE" | matchPattern
done << EOA
    $(awk -F, '{print &7}' $FILEIN)
EOA

其中 matchPattern 是一个匹配模式并进行统计的函数。

现在我有 2 个问题:

1) 如何远程查找最新日志文件? latest 日志文件名匹配 xxxx2012-05-02.log 并且是最新创建的,是否可以远程执行 ls 并找到匹配 xxxx2012-05-02.log 文件名的文件?(I可以在本地执行此操作,但在将其附加到 ssh 命令时会卡住)我可以想出的另一种方法是

cat 'ls -t | head -1'  or
cat $(ls -t | head -1)

但是,如果我将此附加到 ssh,它将列出我本地最新创建的文件名,我们可以将其设置为远程变量,以便 cat 找到正确的文件吗?

2) 由于有近 1000 个主机,我想知道我是否可以并行执行此操作(例如一次执行 20 个 ssh,并在前 20 个完成后执行下一个 20),将 & 附加到每个 ssh 似乎不是完成它就足够了。

任何想法将不胜感激!


跟进: 大家好,我终于找到了一个糟糕的方法来解决第一个问题:

ssh -n name@$host "cd $logDir; cat *$logName" | matchPattern

其中 $logName 是“今天的 date.log”(2012-05-02.log)。问题是我只能在双引号内使用 local 变量。由于我的日志文件以 2012-05-02.log 结尾,并且没有其他文件以这个后缀结尾,所以我只是在远程机器上盲目地执行 cat *2012-05-02.log,它会为我找到所需的文件。

【问题讨论】:

  • 某些版本的 xargs 可能会有所帮助。使用man xargs 并将您的可用选项与您在 S.O. 上找到的建议进行比较。搜索[bash] xargs。祝你好运。
  • 我在 Python 中使用 Threading 和 Paramako 做了几乎完全相同的事情。我可以在 4 分钟内挖出大约 2000 台机器。 (总而言之,我认为使用更好的工具箱可能更容易完成这项任务,我不认为 shell 是合适的工具)
  • @tMC 是的,我可能也在使用 python...但是问题的阈值不是网络连接,它正在解析可能超过 2G 的大日志文件,无论如何我可能会考虑 python作为赌注:)
  • 如果解析文件非常耗时,请在远程节点上进行。如果每个节点处理自己的文件,并行化会更快更容易

标签: linux shell ssh


【解决方案1】:

第一个问题,

ssh -n name@$host 'cat $(ls -t /path/to/log/dir/*.log | head -n 1)'

应该可以。注意远程命令周围的单引号。

对于第二个问题,将所有 ssh | matchPattern | analyse 内容包装到它自己的函数中,然后通过

对其进行迭代
outstanding=0
while read host
do
    sshMatchPatternStuff &
    outstanding=$((outstanding + 1))
    if [ $outstanding -ge 20 ] ; then
        wait
        outstanding=$((outstanding - 1))
    fi
done << EOA
    $(awk -F, '{print &7}' $FILEIN)
EOA
while [ $outstanding -gt 0 ] ; do
    wait
    outstanding=$((outstanding - 1))
done

(我假设您使用的是bash。)

最好将ssh | matchPattern | analyse的东西分离成自己的脚本,然后使用xargs的并行变体来调用它。

【讨论】:

  • 嗨 dave4420,第一个 ssh 对我不起作用 - 因为 $(ls -t /path/to/log/dir/*.log | head -n 1) 试图列出我的本地机器上的文件,而不是远程主机 /path/to/log/dir。尝试您的第二个解决方案,谢谢!
  • 你在本地使用的是哪个shell?单引号应该强制将$(...) 原封不动地发送到远程shell。你确定你使用的是单引号,而不是双引号或反引号?
  • 当我执行 echo $SHELL 时得到 /bin/bash ,是的,我使用的是单引号......对于第二个问题,我写了以下函数 sshMatchPatternStuff() { ssh -n user@$3 "cd $1; cat *$2" | matchPattern } 因为它现在是多线程的,所以我认为我需要将一些参数传递给matchPattern(我之前使用全局变量),但它使用管道,我不能只将参数附加到matchPattern,关于如何做到这一点的任何想法?谢谢!
  • 现在不是多线程,而是多处理:sshMatchPatternStuff 的每次调用都在自己的进程中,并获取自己的全局变量副本。因此,我认为您无需对此进行任何更改。
  • 回复'$(...)':奇怪的是它不适合你。我测试了它,它对我有用。我很困惑。
【解决方案2】:

第二个问题,看看并行分布式shell:

http://sourceforge.net/projects/pdsh/

【讨论】:

  • 感谢 johnshen64,但脚本在我公司的机器上运行,不允许安装 3rd 方程序
  • 哦,在这种情况下,除了尝试在后台运行远程脚本之外,您无能为力。
【解决方案3】:

如果您安装了 GNU Parallel http://www.gnu.org/software/parallel/,您可以这样做:

parallel -j0 --nonall --slf <(awk -F, '{print $7}' servers.txt) 'cd logdir; cat `ls -t | head -1` | grep pattern'

这样您就可以在远程服务器上完成匹配。如果您更喜欢传输完整的日志文件并在本地进行匹配,只需将 grep 移到外面:

parallel -j0 --nonall --slf <(awk -F, '{print $7}' servers.txt) 'cd logdir; cat `ls -t | head -1`' | grep pattern

您可以通过以下方式安装 GNU Parallel:

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
cp parallel sem

观看 GNU Parallel 的介绍视频以了解更多信息: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-17
    • 2018-05-01
    • 1970-01-01
    相关资源
    最近更新 更多