如何在Bash中执行并行的“for”循环?

7

我一直在尝试并行化以下脚本,特别是for循环。我该如何做到这一点?

#!/bin/bash
for i in `cat /root/vms`;
do
    /usr/bin/sshpass -p 'test' /usr/bin/ssh -o StrictHostKeyChecking=no \
        -l testuser $i -t 'echo test | sudo -S yum update -y'
done

for 循环 - 你想要并行运行多个 for 循环吗?那么你应该指定循环的数量。 - RomanPerekhrest
3个回答

5

替换

/usr/bin/sshpass ...

使用

/usr/bin/sshpass ... &

这里的问题是for循环正在串行执行。我想并行执行for循环。 - gosatriani
这就是这个更改所做的事情。如果您的文件/root/vms包含20行,则会启动20个sshpass并行。 - Cyrus
@gosatriani,你是如何实现“串行执行”的?从技术上讲,这种方法将每个命令作为后台任务启动,以并行方式运行。 - RomanPerekhrest

3
你可以使用GNU Parallel来简洁地完成这个任务:
parallel -a /root/vms /usr/bin/sshpass -p \'test\' /usr/bin/ssh -o StrictHostKeyChecking=no -l testuser {} -t \'echo test \| sudo -S yum update -y\'

因此,如果您的/root/vms中包含:
vm-ubuntuLTS
vm-centos
vm-debian
vm-arch

如果你添加--dry-run选项,你可以看到它会执行什么操作,但实际上并不会做任何事情:

parallel --dry-run -a /root/vms /usr/bin/sshpass -p \'test\' /usr/bin/ssh -o StrictHostKeyChecking=no -l testuser {} -t \'echo test \| sudo -S yum update -y\'

样例输出

/usr/bin/sshpass -p 'test' /usr/bin/ssh -o StrictHostKeyChecking=no -l testuser vm-debian -t 'echo test | sudo -S yum update -y'
/usr/bin/sshpass -p 'test' /usr/bin/ssh -o StrictHostKeyChecking=no -l testuser vm-centos -t 'echo test | sudo -S yum update -y'
/usr/bin/sshpass -p 'test' /usr/bin/ssh -o StrictHostKeyChecking=no -l testuser vm-ubuntuLTS -t 'echo test | sudo -S yum update -y'
/usr/bin/sshpass -p 'test' /usr/bin/ssh -o StrictHostKeyChecking=no -l testuser vm-arch -t 'echo test | sudo -S yum update -y'

不要重复所有的ssh选项,考虑将它们放入一个文件中,位置在$HOME/.ssh/config,像这样:
Host vm-centos
HostName vm-centos
User freddy
   StrictHostKeyChecking no

Host vm-arch
HostName vm-arch
   User frog
   Port 2222
   ServerAliveInterval 10

当我使用上述命令时,会出现一些语法错误并行:警告:您正在使用--tollef。如果出现异常情况,请使用--gnu。 并行:警告:--tollef已过时,将于20140222退役。 并行:警告:请参见:http://lists.gnu.org/archive/html/parallel/2013-02/msg00018.html /usr/bin/sshpass: vm-centos:找不到命令 -p:vm-centos:找不到命令 'test':vm-centos:找不到命令 /usr/bin/ssh:vm-centos:找不到命令 -o:vm-centos:找不到命令 - gosatriani
这意味着你的发行版提供了一个旧版本的GNU Parallel。要么更新它,要么只需使用parallel --gnu <OTHER OPTIONS>。你的版本是从2014年的。 - Mark Setchell

0
GNU Parallel有一个--nonall选项和一个环境变量来设置要使用的ssh命令:
PARALLEL_SSH="/usr/bin/sshpass -p test /usr/bin/ssh -o StrictHostKeyChecking=no -l testuser -t"
export PARALLEL_SSH
parallel --slf /root/vms --nonall 'echo test | sudo -S yum update -y'

如果你想要运行的东西比较复杂,你可以编写一个函数,并让GNU Parallel进行传输:
complex_task() {
  # Do complex task
  echo test | sudo -S yum update -y
  # and a lot more complex stuff
}
export -f complex_task
PARALLEL_SSH="/usr/bin/sshpass -p test /usr/bin/ssh -o StrictHostKeyChecking=no -l testuser -t"
export PARALLEL_SSH
parallel --slf /root/vms --env complex_task --nonall complex_task

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