dash 與 ksh 和 bash 中的退出陷阱

dash 與 ksh 和 bash 中的退出陷阱

這是一個簡單的腳本,它在當前目錄中設置一個臨時目錄,並設置一個陷阱在退出時將其刪除。

#filename: script   
set -x  
trap 'rm -rf "$d"' exit
d=`TMPDIR=$PWD mktemp -d`
"$@"

如果我執行ksh script sleep 100orbash script sleep 100並用, 中斷它,C-C則陷阱將被執行並刪除目錄。它不適用於dash.為什麼?這是一個錯誤還是有意的行為?

答案1

zsh, (儘管不是從中派生pdksh的最新版本),, Bourne shell 的行為類似於.mkshyashdash

bashksh88ksh93以及mksh其他行為。

POSIX 規範並不清楚什麼是正確的行為,但其中沒有任何內容表明允許 shell 覆蓋SIGINT(或其他)訊號的預設處理程序。

它說EXIT陷阱操作應該在exit呼叫時進行評估,但據我所知,它甚至沒有說,例如,當 shell 由於set -eset -u或錯誤條件(如語法錯誤或特殊內建函數失敗)而退出時是否應該評估它。

為了能夠EXIT在接收訊號後執行 trap,shell 需要在該訊號上安裝一個處理程序。

這就是kshmkshbash所做的事情,但是它們處理的訊號列表在所有三種實作之間是不同的。這三個訊號之間唯一共同的訊號似乎是INTQUITTERM和。ALRMHUP

如果您希望EXIT陷阱在某些訊號上運行,可移植的方法是您自己處理這些訊號:

trap 'exit 1' INT HUP QUIT TERM ALRM USR1
trap 'cleanup' EXIT

然而,這種方法不適用於,如果從陷阱處理程序調用,zsh則不會執行EXIT陷阱。exit

它也無法向你的父母報告你的死亡訊號。

因此,你可以這樣做:

for sig in INT QUIT HUP TERM ALRM USR1; do
  trap "
    cleanup
    trap - $sig EXIT
    kill -s $sig "'"$$"' "$sig"
done
trap cleanup EXIT

現在,請注意,如果在執行時有更多訊號到達cleanupcleanup則可能會再次運行。cleanup如果多次呼叫和/或在執行期間忽略訊號,您可能希望確保您的工作正常。

答案2

警告:exit不保證有效,您應該使用EXIT

鑑於 POSIX 標準沒有定義EXIT在有訊號的情況下是否也應該執行陷阱,並且考慮到 Bourne ShellEXIT在您提到的情況下不會調用陷阱,很明顯您正在輸入未指定行為。

相關內容