我有一个bash脚本来测试服务器在负载下的执行情况.
num=1
if [ $# -gt 0 ]; then
num=$1
fi
for i in {1 .. $num}; do
(while true; do
{ time curl --silent 'http://localhost'; } 2>&1 | grep real
done) &
done
wait
Run Code Online (Sandbox Code Playgroud)
当我按下Ctrl-C时,主进程退出,但后台循环继续运行.如何让它们全部退出?或者是否有更好的方法来生成可并行执行的可配置数量的逻辑循环?
Rus*_*vis 47
这是一个更简单的解决方案 - 只需在脚本顶部添加以下行:
trap "kill 0" SIGINT
Run Code Online (Sandbox Code Playgroud)
Killing 0将信号发送到当前进程组中的所有进程.
答案有点晚了,但对我来说,解决方案就像kill 0或kill $(jobs -p)走得太远(杀死所有子进程)。
如果您只是想确保一个特定的子进程(及其自己的子进程)得到整理,那么更好的解决方案是使用子进程的 PID 按进程组 (PGID) 进行终止,如下所示:
set -m
./some_child_script.sh &
some_pid=$!
kill -- -${some_pid}
Run Code Online (Sandbox Code Playgroud)
首先,该set -m命令将启用作业管理(如果尚未启用),这很重要,否则所有命令、子 shell 等都将被分配到与父脚本相同的进程组(与运行命令时不同)在终端中手动执行),并且kill只会给出“没有这样的进程”错误。在运行您希望作为一个组管理的后台命令之前需要调用它(或者如果您有多个,则在脚本启动时调用它)。
其次,请注意 的参数kill是否定的,这表明您想要杀死整个进程组。默认情况下,进程组 ID 与组中的第一个命令相同,因此我们只需在使用 获取的 PID 前面添加一个减号即可获得它$!。如果您需要在更复杂的情况下获取进程组 ID,则需要使用ps -o pgid= ${some_pid},然后添加减号。
最后,请注意 options 的显式结尾的使用--,这很重要,否则进程组参数将被视为选项(信号号),并且kill会抱怨它没有足够的参数。仅当进程组参数是您希望终止的第一个进程组参数时才需要此参数。
这是后台超时过程的简化示例,以及如何尽可能清理:
#!/bin/bash
# Use the overkill method in case we're terminated ourselves
trap 'kill $(jobs -p | xargs)' SIGINT SIGHUP SIGTERM EXIT
# Setup a simple timeout command (an echo)
set -m
{ sleep 3600; echo "Operation took longer than an hour"; } &
timeout_pid=$!
# Run our actual operation here
do_something
# Cancel our timeout
kill -- -${timeout_pid} >/dev/null 2>&1
wait -- -${timeout_pid} >/dev/null 2>&1
printf '' 2>&1
Run Code Online (Sandbox Code Playgroud)
这应该可以在所有合理的情况下干净地处理取消这个简单的超时;唯一无法处理的情况是脚本立即终止 ( kill -9),因为它没有机会进行清理。
我还添加了一个wait,后跟一个 no-op ( printf ''),这是为了抑制命令可能引起的“终止”消息kill,这有点像黑客,但根据我的经验,它足够可靠。
| 归档时间: |
|
| 查看次数: |
12368 次 |
| 最近记录: |