用例:
需要将二进制文件(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-其他软件包,例如屏幕。
我尝试了什么:
我当时正在考虑通过循环将一些脚本注入远程节点,以从那里控制执行。但是我敢肯定,应该没有那么野蛮的选择了。
在这里可以做什么?
答案 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文件