我正在尝试编写一个.sh文件,同时运行许多程序
我试过了
prog1
prog2
但是它会运行prog1,然后等待prog1结束,然后启动prog2……
那么如何并行运行呢?
我正在尝试编写一个.sh文件,同时运行许多程序
我试过了
prog1
prog2
但是它会运行prog1,然后等待prog1结束,然后启动prog2……
那么如何并行运行呢?
当前回答
如果你想用ctrl-c轻松地运行和杀死多个进程,这是我最喜欢的方法:在一个(…)subshell中生成多个后台进程,并捕获SIGINT来执行kill 0,这将杀死subshell组中生成的所有内容:
(trap 'kill 0' SIGINT; prog1 & prog2 & prog3)
你可以有复杂的进程执行结构,所有的事情都可以用一个ctrl-c来结束(只要确保最后一个进程是在前台运行的,也就是说,在prog1.3之后不要包含&):
(trap 'kill 0' SIGINT; prog1.1 && prog1.2 & (prog2.1 | prog2.2 || prog2.3) & prog1.3)
如果最后一个命令可能会提前退出,而您希望保持其他所有命令的运行,则添加wait作为最后一个命令。在下面的例子中,sleep 2会先退出,在sleep 4结束之前杀死它;添加wait可以让两者都运行到完成:
(trap 'kill 0' SIGINT; sleep 4 & sleep 2 & wait)
其他回答
#!/bin/bash
prog1 & 2> .errorprog1.log; prog2 & 2> .errorprog2.log
将错误重定向到单独的日志。
并行运行多个程序:
prog1 &
prog2 &
如果你需要脚本等待程序完成,你可以添加:
wait
在您希望脚本等待它们的地方。
xargs -P <n>允许并行运行<n个>命令。
虽然-P是一个非标准选项,但是GNU (Linux)和macOS/BSD实现都支持它。
示例如下:
最多同时运行3个命令, 只有在先前启动的进程终止时才启动附加命令。
time xargs -P 3 -I {} sh -c 'eval "$1"' - {} <<'EOF'
sleep 1; echo 1
sleep 2; echo 2
sleep 3; echo 3
echo 4
EOF
输出如下所示:
1 # output from 1st command
4 # output from *last* command, which started as soon as the count dropped below 3
2 # output from 2nd command
3 # output from 3rd command
real 0m3.012s
user 0m0.011s
sys 0m0.008s
计时显示这些命令是并行运行的(最后一个命令仅在最初3个命令中的第一个命令终止后启动,但执行得非常快)。
xargs命令本身在所有命令完成之前不会返回,但是您可以在后台执行它,使用控制操作符&终止它,然后使用内置的wait等待整个xargs命令完成。
{
xargs -P 3 -I {} sh -c 'eval "$1"' - {} <<'EOF'
sleep 1; echo 1
sleep 2; echo 2
sleep 3; echo 3
echo 4
EOF
} &
# Script execution continues here while `xargs` is running
# in the background.
echo "Waiting for commands to finish..."
# Wait for `xargs` to finish, via special variable $!, which contains
# the PID of the most recently started background process.
wait $!
注意:
BSD/macOS xargs要求您显式地指定并行运行的命令的数量,而GNU xargs允许您指定-P 0以并行运行尽可能多的命令。 并行运行的进程的输出在生成时到达,因此它将不可预测地交错。 正如Ole的回答中所提到的(大多数平台都不是标准的),GNU并行在每个进程的基础上方便地序列化(分组)输出,并提供了许多更高级的特性。
如果你想用ctrl-c轻松地运行和杀死多个进程,这是我最喜欢的方法:在一个(…)subshell中生成多个后台进程,并捕获SIGINT来执行kill 0,这将杀死subshell组中生成的所有内容:
(trap 'kill 0' SIGINT; prog1 & prog2 & prog3)
你可以有复杂的进程执行结构,所有的事情都可以用一个ctrl-c来结束(只要确保最后一个进程是在前台运行的,也就是说,在prog1.3之后不要包含&):
(trap 'kill 0' SIGINT; prog1.1 && prog1.2 & (prog2.1 | prog2.2 || prog2.3) & prog1.3)
如果最后一个命令可能会提前退出,而您希望保持其他所有命令的运行,则添加wait作为最后一个命令。在下面的例子中,sleep 2会先退出,在sleep 4结束之前杀死它;添加wait可以让两者都运行到完成:
(trap 'kill 0' SIGINT; sleep 4 & sleep 2 & wait)
这里有很多有趣的答案,但我从这个答案中获得了灵感,并将一个简单的脚本组合在一起,并行运行多个进程,并在完成后处理结果。你可以在以下要点中找到它:
#!/usr/bin/env bash
# inspired by https://stackoverflow.com/a/29535256/2860309
pids=""
failures=0
function my_process() {
seconds_to_sleep=$1
exit_code=$2
sleep "$seconds_to_sleep"
return "$exit_code"
}
(my_process 1 0) &
pid=$!
pids+=" ${pid}"
echo "${pid}: 1 second to success"
(my_process 1 1) &
pid=$!
pids+=" ${pid}"
echo "${pid}: 1 second to failure"
(my_process 2 0) &
pid=$!
pids+=" ${pid}"
echo "${pid}: 2 seconds to success"
(my_process 2 1) &
pid=$!
pids+=" ${pid}"
echo "${pid}: 2 seconds to failure"
echo "..."
for pid in $pids; do
if wait "$pid"; then
echo "Process $pid succeeded"
else
echo "Process $pid failed"
failures=$((failures+1))
fi
done
echo
echo "${failures} failures detected"
结果是:
86400: 1 second to success
86401: 1 second to failure
86402: 2 seconds to success
86404: 2 seconds to failure
...
Process 86400 succeeded
Process 86401 failed
Process 86402 succeeded
Process 86404 failed
2 failures detected