Bash
dash vs ksh和bash中的退出陷阱
這是一個簡單的腳本,它在目前目錄中設置一個臨時目錄,並在退出時設置一個陷阱來刪除它。
#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
. 為什麼?這是錯誤還是預期行為?
zsh
,pdksh
(雖然不是mksh
從那個派生的最新版本),yash
, Bourne shell 的行為類似於dash
.只有
bash
,ksh88
和ksh93
否則mksh
行為。POSIX 規範不清楚什麼應該是正確的行為,但其中沒有任何內容表明允許 shell 覆蓋
SIGINT
(或其他)信號的預設處理程序。它說
EXIT
陷阱動作應該在exit
被呼叫時進行評估,但是AFAICT,它甚至沒有說例如當shell由於語法錯誤或失敗的特殊內置函式等錯誤條件而退出時是否應該評估set -e
它set -u
。為了能夠
EXIT
在接收到信號時執行陷阱,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
如果多次呼叫和/或在執行期間忽略信號,您可能希望確保您的工作正常。