bash关闭挂钩;或者,在主进程被终止时终止所有后台进程
我有一个bash,它作为后台进程运行无数的命令:bash关闭挂钩;或者,在主进程被终止时终止所有后台进程,bash,process,Bash,Process,我有一个bash,它作为后台进程运行无数的命令: #!/bin/bash function xyz() { # some awk command } endlesscommand "param 1" | xyz & # async pids=$! endlesscommand "param 2" | xyz & # async pids="$pids "$! endlesscommand "param 3" | xyz # sync so the script
#!/bin/bash
function xyz() {
# some awk command
}
endlesscommand "param 1" | xyz & # async
pids=$!
endlesscommand "param 2" | xyz & # async
pids="$pids "$!
endlesscommand "param 3" | xyz # sync so the script doesn't leave
停止此脚本的唯一方法是(必须)Ctrl-C或kill,当这种情况发生时,我需要杀死$pids变量中列出的所有后台进程
我该怎么做
如果可以捕获主进程上的kill信号,并在该信号发生时执行一个函数(shutdownhook),我将执行如下操作:
for $pid in $pids; do kill $pid; done;
但我找不到该怎么做
kill `ps axl | grep "endlesscommand" | awk '{printf $4" "}'`
这将查找影响“endlesscommand”的父进程这里有一个不需要跟踪PID的陷阱:
trap 'jobs -p | xargs kill' EXIT
编辑:@Barmar询问这是否适用于非源代码脚本,而这些脚本通常不提供作业控制。是的。考虑这个脚本:
$ cat no-job-control
#! /bin/bash
set -e -o pipefail
# Prove job control is off
if suspend
then
echo suspended
else
echo suspension failed, job control must be off
fi
echo
# Set up the trap
trap 'jobs -p | xargs kill' EXIT
# Make some work
(echo '=> Starting 0'; sleep 5; echo '=> Finishing 0') &
(echo '=> Starting 1'; sleep 5; echo '=> Finishing 1') &
(echo '=> Starting 2'; sleep 5; echo '=> Finishing 2') &
echo "What's in jobs -p?"
echo
jobs -p
echo
echo "Ok, exiting now"
echo
运行时,我们看到三个组长的PID,然后看到他们被杀:
$ ./no-job-control
./no-job-control: line 6: suspend: cannot suspend: no job control
suspension failed, job control must be off
=> Starting 0
What's in jobs -p?
=> Starting 1
54098
54099
54100
Ok, exiting now
=> Starting 2
./no-job-control: line 31: 54098 Terminated: 15 ( echo '=> Starting 0'; sleep 5; echo '=> Finishing 0' )
./no-job-control: line 31: 54099 Terminated: 15 ( echo '=> Starting 1'; sleep 5; echo '=> Finishing 1' )
./no-job-control: line 31: 54100 Terminated: 15 ( echo '=> Starting 2'; sleep 5; echo '=> Finishing 2' )
如果我们改为注释掉陷阱
行并重新运行,这三个作业不会消失,事实上,几秒钟后打印出它们的最终消息。请注意,返回的提示与最终输出交织在一起
$ ./no-job-control
./no-job-control: line 6: suspend: cannot suspend: no job control
suspension failed, job control must be off
=> Starting 0
What's in jobs -p?
54110
54111
54112
=> Starting 1
Ok, exiting now
=> Starting 2
$ => Finishing 0
=> Finishing 2
=> Finishing 1
您可以使用pgrep和一个函数来终止在主进程下创建的所有进程,如下所示。这不仅会杀死直接子进程,还会杀死在其下创建的子进程
#!/bin/bash
function killchildren {
local LIST=() IFS=$'\n' A
read -a LIST -d '' < <(exec pgrep -P "$1")
local A SIGNAL="${2:-SIGTERM}"
for A in "${LIST[@]}"; do
killchildren_ "$A" "$SIGNAL"
done
}
function killchildren_ {
local LIST=()
read -a LIST -d '' < <(exec pgrep -P "$1")
kill -s "$2" "$1"
if [[ ${#LIST[@]} -gt 0 ]]; then
local A
for A in "${LIST[@]}"; do
killchildren_ "$A" "$2"
done
fi
}
trap 'killchildren "$BASHPID"' EXIT
endlesscommand "param 1" &
endlesscommand "param 2" &
endlesscommand "param 3" &
while pgrep -P "$BASHPID" >/dev/null; do
wait
done
原始函数参考:您需要使用陷阱…不需要维护子进程的显式列表;您可以调用
jobs-p
获取仍在运行的子进程的进程ID。kill-9
不能轻易使用。一个简单的kill
就足够了。此外,这会杀死所有运行endlesscommand
的进程,而不仅仅是那些由被杀死的父进程启动的进程。@chepner对于派生的进程不正确。。。OP想要杀死所有涉及的进程,所以我不明白为什么kill-9
是不安全的?kill-9
没有给被杀死的进程任何机会在其自身之后进行清理:关闭文件、刷新缓冲区等。我尝试了最后一个解决方案,它工作正常。。。但如果我的endlesscommand与其他程序/函数通过管道传输(我更新了我的问题),则不会。最后,我使用的是您的pgrep环路和phs解决方案,效果非常好。:)谢谢,即使使用管道,效果也很好!:)它甚至可以更短:trap'jobs-p | xargs kill'EXITDoesjobs-p
在脚本中真的有效,即使它们没有启用作业控制?是的,我在发布评论后自己做了一个简单的测试。令人惊讶的
#!/bin/bash
trap 'kill "${pids[@]}"' EXIT
pids=()
endlesscommand "param 1" & # async
pids+=("$!")
endlesscommand "param 2" & # async
pids+=("$!")
endlesscommand "param 3" & # syncing this is not a good idea since if the main process would end along with it if it ends earlier.
pids+=("$!")
while pgrep -P "$BASHPID" >/dev/null; do
wait
done