[英]Bash trap not killing children, causes unexpected ctrl-c behavior
編輯
對於未來的讀者。 這個問題的根源實際上在於在交互式外殼程序中運行該功能,而不是將其放在單獨的腳本中。
另外,在我最初發布的代碼中,還有很多可以改進的地方。 請查看評論,以了解本來可以/應該做得更好的事情。
/編輯
我有一個bash函數,用於在目錄中的文件更改時在后台重新運行進程(以Grunt為例,但出於一般目的)。 該腳本在運行時可根據需要運行:
但是,在退出(ctrl-c)時,不會殺死任何進程。 此外,再次按ctrl-c將終止當前的終端會話。 我以為這是我的陷阱存在的問題,但是無法確定問題的原因。
這是rerun.sh的代碼
#!/bin/bash
# rerun.sh
_kill_children() {
isTop=$1
curPid=$2
# Get pids of children
children=`ps -o pid --no-headers --ppid ${curPid}`
for child in $children
do
# Call this function to get grandchildren as well
_kill_children 0 $child
done
# Parent calls this with 1, all other with 0 so only children are killed
if [[ $isTop -eq 0 ]]; then
kill -9 $curPid 2> /dev/null
fi
}
rerun() {
trap " _kill_children 1 $$; exit 0" SIGINT SIGTERM
FORMAT=$(echo -e "\033[1;33m%w%f\033[0m written")
#Command that should be repeatedly run is passed as args
args=$@
$args &
#When a file changes in the directory, rerun the process
while inotifywait -qre close_write --format "$FORMAT" .
do
#Kill current bg proc and it's children
_kill_children 1 $$
$args & #Rerun the proc
done
}
#This is sourced in my bash profile so I can run it any time
要對此進行測試,請創建一對可執行文件parent.sh和child.sh,如下所示:
#!/bin/bash
#parent.sh
./child.sh
#!/bin/bash
#child.sh
sleep 86400
然后獲取rerun.sh文件並運行rerun ./parent.sh
。 在另一個終端窗口中,我watch "ps -ef | grep pts/4"
以查看重新運行的所有進程(在此示例中為pts / 4)。 觸摸目錄中的文件會觸發parent.sh和子級的重新啟動。 [ctrl-c]退出,但讓pid運行。 [ctrl-c]再次殺死pts / 4上的bash和所有其他進程。
所需的行為:在[ctrl-c]上,殺死孩子並正常退出外殼。 救命?
-代碼來源:
從以下途徑獲得想法: https : //exyr.org/2011/inotify-run/
殺死孩子: http : //riccomini.name/posts/linux/2012-09-25-kill-subprocesses-linux-bash/
首先,這不是一個好的做法。 明確跟蹤孩子:
children=( )
foo & children+=( "$!" )
...然后,您可以明確殺死它們或等待它們,請參閱列表的"${children[@]}"
。 如果您也想獲得孫子代,那么這是使用fuser -k
和lockfile的好用戶:
lockfile_name="$(mktemp /tmp/lockfile.XXXXXX)" # change appropriately
trap 'rm -f "$lockfile_name"' 0
exec 3>"$lockfile_name" # open lockfile on FD 3
kill_children() {
# close our own handle on the lockfile
exec 3>&-
# kill everything that still has it open (our children and their children)
fuser -k "$lockfile_name" >/dev/null
# ...then open it again.
exec 3>"$lockfile_name"
}
rerun() {
trap 'kill_children; exit 0' SIGINT SIGTERM
printf -v format '%b' "\033[1;33m%w%f\033[0m written"
"$@" &
#When a file changes in the directory, rerun the process
while inotifywait -qre close_write --format "$format" .; do
kill_children
"$@" &
done
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.