回答
要清理一些爛攤子,可以使用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. 退出與後臺進程shell腳本
- 3. 如何從shell腳本中退出時終止所有子進程?
- 4. 後臺shell腳本自動終止
- 5. shell腳本殺死後臺進程上退出
- 6. cron作業腳本終止
- 7. bash腳本SFTP退出終止腳本
- 8. 如何控制shell腳本中後臺作業的數量
- 9. 後臺進程在其父進程終止時被終止?
- 10. 從作爲後臺作業運行的shell腳本生成進程
- 11. 如何在bash腳本退出時終止ssh隧道子進程
- 12. 如何退出/暫停/終止/終止/停止MSBuild進程?
- 13. bash編程,後臺進程,PID和等待作業退出
- 14. 爲什麼Applescript在後臺Shell作業後退出?
- 15. 退出基於進程的Shell腳本退出代碼
- 16. 如何在後臺進程在Perl中終止時通知我?
- 17. 如何在Android應用程序退出後終止進程?
- 18. 紅寶石 - 當主線程退出時不要終止進程
- 19. 如何使用groovy腳本控制檯來終止Jenkins作業後遺留的進程?
- 20. 如何運行本身啓動兩個後臺進程的後臺shell腳本?
- 21. 當退出時終止在xterm內啓動的所有進程
- 22. 執行腳本後終止PowerShell進程
- 23. 如何在指定時間後終止shell腳本
- 24. shell腳本退出
- 25. 如何知道當退出進入工作時腳本應該退出?
- 26. 腳本退出後如何退出終端?
- 27. 當作業不收斂時,Abaqus過早終止python腳本
- 28. 如何阻止子進程終止我的腳本?
- 29. 後臺進程終止後的通知
- 30. 如何在退出iterm 2時關閉後臺作業?
那麼你怎麼killall *孩子*只? (或者我錯過了一些明顯的東西) – elmarco 2008-12-11 20:51:01
killall殺死你的孩子,但不是你 – orip 2008-12-11 22:10:56
elmarco,更新回答 – 2008-12-12 16:33:21