回答
要清理一些烂摊子,可以使用trap
。它可以提供的执行功能的列表,当一个特定的信号到达:
trap "echo hello" SIGINT
,但也可以使用,如果在shell退出执行的东西:
trap "killall background" EXIT
这是一个内置的,所以help trap
会给你信息(与bash一起工作)。如果你只是想杀死后台作业,你可以做
trap 'kill $(jobs -p)' EXIT
当心使用单一'
,以防止shell立即替换$()
。
因此脚本加载脚本。运行一个killall
(或任何在您的操作系统上可用的)命令,脚本完成后立即执行。
另一个选择是让脚本将自己设置为进程组组长,并在退出时在进程组中捕获killpg。
陷阱“杀死$(工种-p)” EXIT
我会做给约翰的回答和使用工作只有轻微的变化-PR给杀限制正在运行的进程,并添加几个信号到列表:
trap 'kill $(jobs -pr)' SIGINT SIGTERM EXIT
工作-p并不适用于所有壳工作,如果调用一个子shell,可能除非它的输出重定向到一个文件,但不是一个烟斗。 (我假设它最初仅用于交互使用。)
什么如下:
trap 'while kill %% 2>/dev/null; do jobs > /dev/null; done' INT TERM EXIT [...]
调用到“工作”需要符合Debian的仪表板外壳,从而未能更新当前的工作( “%%”)如果它丢失。
为了安全起见,我觉得它更好地定义清理功能和陷阱调用它:
cleanup() {
local pids=$(jobs -pr)
[ -n "$pids" ] && kill $pids
}
trap "cleanup" INT QUIT TERM EXIT [...]
或完全避免功能:
trap '[ -n "$(jobs -pr)" ] && kill $(jobs -pr)' INT QUIT TERM EXIT [...]
为什么?因为通过简单地使用trap 'kill $(jobs -pr)' [...]
,假设有将作为发送陷阱条件时运行的后台作业。当没有工作一个将看到以下(或类似)消息:
kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
因为jobs -pr
是空的 - 我结束了在“陷阱”(双关语意)。
trap "exit" INT TERM
trap "kill 0" EXIT
为什么要转变INT
和TERM
退出?因为两者都应触发kill 0
而不进入无限循环。
为什么在EXIT
上触发kill 0
?因为正常的脚本退出也应该触发kill 0
。
为什么kill 0
?因为嵌套的子壳也需要被杀死。这将取下the whole process tree。
@tokland's answer中描述的trap 'kill 0' SIGINT SIGTERM EXIT
解决方案非常好,但使用它时最新的Bash crashes with a segmantation fault。这是因为击,从V 4.3开始,允许陷阱递归,成为在此情况下无限:
- 壳过程临危
SIGINT
或SIGTERM
或EXIT
; - 信号被捕获,执行
kill 0
,发送SIGTERM
到组中的所有进程,包括shell本身; - 去1 :)
这可以通过周围进行加工手动取消注册陷阱:
trap 'trap - SIGTERM && kill 0' SIGINT SIGTERM EXIT
更花哨的方式,允许打印收到的信号和避免“终止” 消息:
#!/usr/bin/env bash
trap_with_arg() { # from https://stackoverflow.com/a/2183063/804678
local func="$1"; shift
for sig in "[email protected]"; do
trap "$func $sig" "$sig"
done
}
stop() {
trap - SIGINT EXIT
printf '\n%s\n' "recieved $1, killing children"
kill -s SIGINT 0
}
trap_with_arg 'stop' EXIT SIGINT SIGTERM SIGHUP
{ i=0; while ((++i)); do sleep 0.5 && echo "a: $i"; done } &
{ i=0; while ((++i)); do sleep 0.6 && echo "b: $i"; done } &
while true; do read; done
UPD:加入迷你一个例子;改进了stop
函数以避免不必要的信号,并隐藏输出中的“Terminated:”消息。谢谢Trevor Boyd Smith的建议!
我做了@ tokland的答案与知识相结合的适应从http://veithen.github.io/2014/11/16/sigterm-propagation.html时,我注意到,如果我运行一个前台进程(不与&
转到后台)trap
不会触发:
#!/bin/bash
# killable-shell.sh: Kills itself and all children (the whole process group) when killed.
# Adapted from http://stackoverflow.com/a/2173421 and http://veithen.github.io/2014/11/16/sigterm-propagation.html
# Note: Does not work (and cannot work) when the shell itself is killed with SIGKILL, for then the trap is not triggered.
trap "trap - SIGTERM && echo 'Caught SIGTERM, sending SIGTERM to process group' && kill -- -$$" SIGINT SIGTERM EXIT
echo [email protected]
"[email protected]" &
PID=$!
wait $PID
trap - SIGINT SIGTERM EXIT
wait $PID
例它的工作:
$ bash killable-shell.sh sleep 100
sleep 100
^Z
[1] + 31568 suspended bash killable-shell.sh sleep 100
$ ps aux | grep "sleep"
niklas 31568 0.0 0.0 19640 1440 pts/18 T 01:30 0:00 bash killable-shell.sh sleep 100
niklas 31569 0.0 0.0 14404 616 pts/18 T 01:30 0:00 sleep 100
niklas 31605 0.0 0.0 18956 936 pts/18 S+ 01:30 0:00 grep --color=auto sleep
$ bg
[1] + 31568 continued bash killable-shell.sh sleep 100
$ kill 31568
Caught SIGTERM, sending SIGTERM to process group
[1] + 31568 terminated bash killable-shell.sh sleep 100
$ ps aux | grep "sleep"
niklas 31717 0.0 0.0 18956 936 pts/18 S+ 01:31 0:00 grep --color=auto sleep
一个很好的版本,在Linux,BSD和MacOS X的第一部作品试图发送SIGTERM,如果没有成功,10秒后终止进程。
KillJobs() {
for job in $(jobs -p); do
kill -s SIGTERM $job > /dev/null 2>&1 || (sleep 10 && kill -9 $job > /dev/null 2>&1 &)
done
}
TrapQuit() {
# Whatever you need to clean here
KillJobs
}
trap TrapQuit EXIT
请注意,作业不包括大孩子的过程。
- 1. 如何控制shell脚本中后台作业的数量
- 2. 后台进程在其父进程终止时被终止?
- 3. 从作为后台作业运行的shell脚本生成进程
- 4. 如何在bash脚本退出时终止ssh隧道子进程
- 5. 如何退出/暂停/终止/终止/停止MSBuild进程?
- 6. 为什么Applescript在后台Shell作业后退出?
- 7. 退出基于进程的Shell脚本退出代码
- 8. 如何在后台进程在Perl中终止时通知我?
- 9. 如何在Android应用程序退出后终止进程?
- 10. 红宝石 - 当主线程退出时不要终止进程
- 11. 如何使用groovy脚本控制台来终止Jenkins作业后遗留的进程?
- 12. 当退出时终止在xterm内启动的所有进程
- 13. shell脚本退出
- 14. 当作业不收敛时,Abaqus过早终止python脚本
- 15. 如何阻止子进程终止我的脚本?
- 16. 杀死调用shell进程的Python脚本是否也会终止shell进程?
- 17. 退出PHP脚本后终止或停止MySQL查询
- 18. 强制终止进程时的进程退出代码
- 19. 在进程终止时运行脚本
- 20. 当Java进程被终止时,java调用的shell脚本是否会被终止?
- 21. shell - 获取后台进程的退出代码
- 22. 当Linux中的另一个进程结束时终止后台进程
- 23. 很好地终止后台python脚本
- 24. 可以退出()无法终止进程?
- 25. Python终止进程退出代码-1073741819
- 26. 如何编写将以编程方式终止进程的shell脚本?
- 27. 如何让退出shell的Python脚本退出?
- 28. 当Asp.net终止后台线程?
- 29. 调用另一个脚本后退出循环的Shell脚本
- 30. 使用shell脚本来自动终止进程
那么你怎么killall *孩子*只? (或者我错过了一些明显的东西) – elmarco 2008-12-11 20:51:01
killall杀死你的孩子,但不是你 – orip 2008-12-11 22:10:56
elmarco,更新回答 – 2008-12-12 16:33:21