BASH:无需等待即可同时执行多循环功能

时间:2018-08-01 03:56:11

标签: linux bash

用例:

需要将二进制文件(1Gb)传输到IP阵列,并在到达目的地后开始执行它们,而不必等待所有二进制文件被传输/执行。某种并行模式。

情况:

我有2个功能-传输和执行(根据方法的不同,可以通过2个循环将其缩短为1个)。

for N in "${NODES[@]}"; do
    rsync -Pcz -e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" --timeout=10 $FILE user@$N
done 

for N in "${NODES[@]}"; do
    ssh user@$N "cd ~/; ./exec.sh"
done 

要点是,在这种情况下,我必须等到所有传输先完成(有时可能会有数十个地址),然后才开始执行。

如果我将循环组合成一个循环,则我不得不再次等待-这次是每个节点的传输和执行。

期望:

我想将文件传输到第一个节点,开始执行,然后以相同的过程切换到第二个节点,依此类推。因此,计时仅会计入传输,而每个节点将并行执行文件。

障碍物:

1-需要能够从每个节点获得执行输出

不能选择

2-其他软件包,例如屏幕

我尝试了什么:

我当时正在考虑通过循环将一些脚本注入远程节点,以从那里控制执行。但是我敢肯定,应该没有那么野蛮的选择了。

在这里可以做什么?

2 个答案:

答案 0 :(得分:1)

您应该能够使用单个循环,并使用带有后缀ssh的{​​{1}}命令,该后缀在后台运行(即,无需等待其完成),然后循环使用&等待它们全部完成。收集输出将更加有趣……我想您需要将每次运行的输出收集到一个文件中,然后在最后打印文件。这样的事情(请注意,我没有对此进行了正确的测试):

wait

顺便说一句,远程命令tmpdir="$(mktemp -qd -t "$(basename "$0")")" || { echo "Error creating temporary directory" >&2 exit 1 } for nodenum in "${!NODES[@]}"; do # The ${!array[@]} idiom gets a list of array *indexes*, not elements; get the element by index: N=${NODES[nodenum]} # Copy file, and wait for copy to finish: rsync -Pcz -e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" --timeout=10 $FILE user@$N # Start the script, and *don't* wait for it to finish: ssh user@$N "cd ~/ sh exec.sh" >"$tmpdir/$nodenum.out" 2>&1 & done # Wait for all of the scripts to finish wait # Print all of the outputs (in order) for nodenum in "${!NODES[@]}"; do echo echo "Output from ${NODES[nodenum]}:" cat "$tmpdir/$nodenum.out" done # Clean up the temp directory rm -R "$tmpdir" 没有任何意义。那里应该有分号吗?另外,我建议使用小写或大小写混合的变量名,以避免与具有某种特殊含义的许多全大写字母变量发生冲突,并在变量引用(即"cd ~/ sh exec.sh"而不是{{1 }}。

编辑:假定您要在完成特定副本后立即在每个主机上启动脚本;如果您要等到所有复制完成,然后立即触发所有脚本,请使用两个循环:一个循环进行复制,然后第二个循环在后台执行rsync ... "$FILE" "user@$N"命令(如上所述收集输出),然后等待所有输出完成,然后打印所有输出。

答案 1 :(得分:0)

您可以将传输和脚本作为单个后台任务来执行,以便特定主机上的脚本在传输完成后立即启动

for N in "${NODES[@]}"; do
    (rsync -Pcz -e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" --timeout=10 $FILE user@$N
     ssh user@$N "cd ~/; ./exec.sh") > ${N}.log 2>&1 &
done

然后收集所有hostname.log文件