簡體   English   中英

Bash陷阱無法殺死孩子,導致意外的ctrl-c行為

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM