簡體   English   中英

bash:可能需要雙Ctrl-c才能退出腳本?

[英]bash: Possible to require double Ctrl-c to to exit a script?

結束目標:等待后台作業完成的BASH腳本不會在第一個Ctrl-c中止; 相反,它需要第二個Ctrl-c退出。

我很清楚BASH內置trap工作原理。 你可以:

  1. 用它來完全忽略一個信號(例如, trap '' 2 )......或

  2. 在允許信號原始函數發生之前使用它來執行任意命令(例如, trap cmd 2 ,其中cmd在父腳本因SIGINT而被中斷之前運行)

所以問題歸結為:

我怎樣才能有效地結合1&2一起,即防止最終結果的信號會導致(1 -例如,停止腳本抵消由於SIGINT ),同時也使該信號引起其他的東西(2 -例如,增量一個櫃台,檢查櫃台並有條件地打印警告或退出)。

更簡單地說:

我怎樣才能發出信號呢? 不只是在它完成它之前插入一個工作。

這是一些示例代碼,用於演示我的目標; 然而,它當然不起作用 - 因為trap只能從上面做12

#!/bin/bash
declare -i number_of_times_trap_triggered
cleanup_bg_jobs() {
    number_of_times_trap_triggered+=1
    if [[ ${number_of_times_trap_triggered} -eq 1 ]]; then
        echo "There are background jobs still running"
        echo "Hit Ctrl-c again to cancel all bg jobs & quit"
    else
        echo "Aborting background jobs"
        for pid in ${bg_jobs}; do echo "  Killing ${pid}"; kill -9 ${pid}; done
    fi
}
f() { sleep 5m; }
trap cleanup_bg_jobs 2
bg_jobs=
for job in 1 2 3; do
    f &
    bg_jobs+=" $!"
done
wait

因此,當您按Ctrl-c一次時,這是您最終獲得的輸出。

[rsaw:~]$ ./zax 
^CThere are background jobs still running
Hit Ctrl-c again to cancel all bg jobs & quit
[rsaw:~]$ ps axf|tail -6 
24569 pts/3    S      0:00 /bin/bash ./zax
24572 pts/3    S      0:00  \_ sleep 5m
24570 pts/3    S      0:00 /bin/bash ./zax
24573 pts/3    S      0:00  \_ sleep 5m
24571 pts/3    S      0:00 /bin/bash ./zax
24574 pts/3    S      0:00  \_ sleep 5m

當然我可以修改它來清理第一個Ctrl-c上的作業,但這不是我想要的。 我想在觸發第一個陷阱后停止BASH退出......直到第二次觸發它為止。

PS:目標平台是Linux(我不太關心POSIX合規性)與BASH v4 +

我在這里做了類似的事情,它主要分解為:

    ATTEMPT=0
handle_close() {
    if [ $ATTEMPT -eq 0 ]; then
        ATTEMPT=1
        echo "Shutdown."
    else
        echo "Already tried to shutdown. Killing."
        exit 0
    fi
}
trap handle_close SIGINT SIGTERM

您可以在處理程序中設置一個變量,您可以在下次捕獲時再次檢查該變量。

我有一個稍微不同的用例,並希望將解決方案留在這里,因為谷歌引導我進入這個主題。 您可以繼續運行命令,並允許用戶使用一個CTRL+C重新啟動它,並使用雙CTRL+C以下列方式將其終止:

trap_ctrlC() {
    echo "Press CTRL-C again to kill. Restarting in 2 second"
    sleep 2 || exit 1
}

trap trap_ctrlC SIGINT SIGTERM

while true; do  
    ... your stuff here ...
done

一位同事(格雷加)剛剛給了我一個解決方案......我無法相信我沒有先想到它。

“我的方法是......使用一個永遠不會返回的函數或另一個函數(另一個等待?),將它永久地擱置,可能是永遠的,以便第二個處理程序可以正常工作。”

為了記錄, wait在這里不起作用。 (遞歸。)但是,在我的原始代碼的cleanup_bg_jobs()函數中添加一個sleep命令會處理它...但會導致孤立的進程。 因此,我利用進程組來確保腳本的所有子項確實被殺死。 后人的簡化示例:

#!/bin/bash
declare -i count=
handle_interrupt() {
    count+=1
    if [[ ${count} -eq 1 ]]; then
        echo "Background jobs still running"
        echo "Hit Ctrl-c again to cancel all bg jobs & quit"
        sleep 1h
    else
        echo "Aborting background jobs"
        pkill --pgroup 0
    fi
}
f() { tload &>/dev/null; }
trap handle_interrupt 2
for job in 1 2 3; do
    f &
done
wait
  1. 在允許信號原始函數發生之前使用它來執行任意命令(例如,陷阱cmd 2,其中cmd 在父腳本因SIGINT而被中斷之前運行

上面的斜體部分是不正確的。 運行陷阱處理程序而不是讓SIGINT(或其他)中斷進程。 更精確地:

  • SIGINT(以及大多數,但不是全部,其他信號)的默認操作是終止進程
  • trap "command" SIGINT導致運行command而不是默認操作( 不如

因此,安裝了SIGINT處理程序后,SIGINT不會中斷整個腳本。 但它中斷wait命令。 陷阱處理程序完成后,腳本會在wait后恢復,即它從結束時退出並正常退出。 你可以通過添加一些調試代碼來看到這個:

echo Waiting
wait
echo Back from wait
exit 55                   # Arbitrary value that wouldn't otherwise occur

此版本產生以下內容:

$ foo
Waiting
^CThere are background jobs still running
Hit Ctrl-c again to cancel all bg jobs & quit
back from wait
$ echo $?
55
$ 

您需要做的是在處理程序返回后重復wait 這個版本:

#!/bin/bash
declare -i number_of_times_trap_triggered
cleanup_bg_jobs() {
    number_of_times_trap_triggered+=1
    if [[ ${number_of_times_trap_triggered} -eq 1 ]]; then
        echo "There are background jobs still running"
        echo "Hit Ctrl-c again to cancel all bg jobs & quit"
    else
        echo "Aborting background jobs"
        for pid in ${bg_jobs}; do echo "  Killing ${pid}"; kill -9 ${pid}; done
        exit 1
    fi
}
f() { sleep 5m; }
trap cleanup_bg_jobs 2
bg_jobs=
for job in 1 2 3; do
    f &
    bg_jobs+=" $!"
done

while [ 1 ]; do
    echo Waiting
    wait
    echo Back from wait
done

按你的要求做:

$ ./foo
Waiting
^CThere are background jobs still running
Hit Ctrl-c again to cancel all bg jobs & quit
Back from wait
Waiting
^CAborting background jobs
  Killing 24154
  Killing 24155
  Killing 24156
$ 

筆記:

  • 我已經離開了調試的東西; 顯然你會在生產中刪除它
  • 處理程序現在在終止子進程后exit 1 這就是突破無限主循環的原因

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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