這是一個簡單的腳本,它在當前目錄中設置一個臨時目錄,並設置一個陷阱在退出時將其刪除。
#filename: script
set -x
trap 'rm -rf "$d"' exit
d=`TMPDIR=$PWD mktemp -d`
"$@"
如果我執行ksh script sleep 100
orbash script sleep 100
並用, 中斷它,C-C
則陷阱將被執行並刪除目錄。它不適用於dash
.為什麼?這是一個錯誤還是有意的行為?
答案1
zsh
, (儘管不是從中派生pdksh
的最新版本),, Bourne shell 的行為類似於.mksh
yash
dash
僅bash
、ksh88
、ksh93
以及mksh
其他行為。
POSIX 規範並不清楚什麼是正確的行為,但其中沒有任何內容表明允許 shell 覆蓋SIGINT
(或其他)訊號的預設處理程序。
它說EXIT
陷阱操作應該在exit
呼叫時進行評估,但據我所知,它甚至沒有說,例如,當 shell 由於set -e
或set -u
或錯誤條件(如語法錯誤或特殊內建函數失敗)而退出時是否應該評估它。
為了能夠EXIT
在接收訊號後執行 trap,shell 需要在該訊號上安裝一個處理程序。
這就是ksh
、mksh
和bash
所做的事情,但是它們處理的訊號列表在所有三種實作之間是不同的。這三個訊號之間唯一共同的訊號似乎是INT
、QUIT
、TERM
和。ALRM
HUP
如果您希望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
現在,請注意,如果在執行時有更多訊號到達cleanup
,cleanup
則可能會再次運行。cleanup
如果多次呼叫和/或在執行期間忽略訊號,您可能希望確保您的工作正常。
答案2
警告:exit
不保證有效,您應該使用EXIT
鑑於 POSIX 標準沒有定義EXIT
在有訊號的情況下是否也應該執行陷阱,並且考慮到 Bourne ShellEXIT
在您提到的情況下不會調用陷阱,很明顯您正在輸入未指定行為。