sigterm 上的 bash 行為

sigterm 上的 bash 行為

有一個腳本如下:

#!/bin/bash
#
# run this script.  don't run it if it's already running.
#

PIDFILE=/tmp/script.pid
LOGFILE=script.log


if [[ -f $PIDFILE ]]; then
    echo "$PIDFILE exists.  Not going to run..."
    exit 0
fi

sleep 10m >> $LOGFILE 2>&1 &
PID=$!
echo $PID > $PIDFILE

trap "echo Exiting...; rm $PIDFILE; exit $?" INT TERM EXIT KILL

wait $PID

我呼叫這個腳本如下:

timeout 2m ./test_script

逾時或 ctrl+c 時,腳本會列印“Exiting”兩次。

# timeout 2m ./test_script
^CExiting...
Exiting...
rm: cannot remove `/tmp/script.pid': No such file or directory

以下是 strace 的輸出和更多數據:

# ps -ef | grep -v grep | egrep -i "sleep|time"
root      8571  4690  0 12:17 pts/0    00:00:00 timeout 2m ./test_script
root      8572  8571  0 12:17 pts/0    00:00:00 /bin/bash ./test_script
root      8573  8572  0 12:17 pts/0    00:00:00 sleep 10m
# cat /tmp/script.pid
8573
# strace -p 8571
Process 8571 attached - interrupt to quit
wait4(-1, 0x7fffc43fad4c, 0, NULL)      = ? ERESTARTSYS (To be restarted)
--- SIGINT (Interrupt) @ 0 (0) ---
kill(0, SIGINT)                         = 0
kill(0, SIGCONT)                        = 0
--- SIGCONT (Continued) @ 0 (0) ---
rt_sigreturn(0)                         = 61
--- SIGINT (Interrupt) @ 0 (0) ---
rt_sigreturn(0x2)                       = 61
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 8572
--- SIGCHLD (Child exited) @ 0 (0) ---
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
Process 8571 detached

有人可以幫助我理解為什麼腳本兩次捕獲信號以打印“Exiting...”兩次的內部原理嗎?

答案1

如果您將trap語句替換為以下三行:

trap "echo Exiting... INT;  exit $?" INT
trap "echo Exiting... TERM; exit $?" TERM
trap "echo Exiting... EXIT; exit $?" EXIT

你會得到輸出

Exiting... TERM
Exiting... EXIT

由此我們可以推斷出

  • trap … TERM語句使 shell 捕獲 SIGTERM 訊號。timeout當逾時到期時,該命令會向進程發送 SIGTERM(預設)。因此 shell 捕獲信號並執行指定的命令,包括echorm(在您的實際腳本中) 和exit.
  • trap … EXIT語句使 shell 給自己留下一張便利貼,上面寫著「記住在我回家之前執行此操作」。因此,當 SIGTERM 陷阱執行exit指令時,EXIT 陷阱也會被執行。
  • 當 EXIT 陷阱執行exit命令時,腳本實際上退出,而不是執行 EXIT 陷阱並進入遞歸地獄。

如果在腳本執行時鍵入Ctrl+ ,您將收到 INT 陷阱,然後是 EXIT 陷阱。如果您在沒有或逾時持續時間長於睡眠時間的情況下C執行腳本,您將僅收到 EXIT 陷阱。timeout

可能足以說

trap "exit $?" INT TERM
trap "echo Exiting...; rm $PIDFILE" EXIT

我認為 EXIT 陷阱不需要執行,因為您透過執行命令(包括腳本末尾的隱式命令)exit進入 EXIT 陷阱,因此,當您執行完 EXIT 陷阱(和)時, shell 除了退出之外沒有什麼可做的。唯一的問題是腳本以什麼退出狀態退出。而且,如果您正在保存一些退出狀態值並執行 ,這可能會很有趣。但只要您正在談論,腳本就可能會以;的退出狀態退出。如果這是您執行的最後一個命令,則預設情況下可能會發生這種情況。exitechormrm $PIDFILE; exit $saved_statusrm $PIDFILE; exit $?rmrm

我做了一些快速測試,結果顯示可以省略

trap "exit" INT TERM

命令,但我不明白。 YMMV。


PS 正如湯瑪斯所說,trap … KILL是無效的。

相關內容