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 时,脚本会打印两次“退出”。

# 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

有人能帮助我理解为什么脚本两次捕获信号以打印“退出...”两次的内部原因吗?

答案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+ C,您将获得 INT 陷阱,然后是 EXIT 陷阱。如果您在不使用 的情况下运行脚本timeout,或者超时持续时间长于睡眠时间,您将只获得 EXIT 陷阱。

也许可以说

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

我认为 EXIT 陷阱不需要执行exit,因为您通过执行exit命令(包括脚本末尾的隐式命令)进入 EXIT 陷阱,因此,当您完成执行 EXIT 陷阱(echorm)时,shell 除了退出之外无需再做任何事情。唯一的问题是脚本以什么退出状态退出。并且,如果您保存了某些退出状态值并执行 rm $PIDFILE; exit $saved_status,那可能会很有趣。但只要您谈论的是rm $PIDFILE; exit $?,脚本可能会以的退出状态退出;如果是您执行的最后一个命令,rm则默认情况下可能会发生这种情况。rm

我做了一些快速测试,结果表明可以省略

trap "exit" INT TERM

命令,但我不明白。YMMV。


PS 正如托马斯所说,trap … KILL是无效的。

相关内容