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 需要在该信号上安装一个处理程序。

这就是kshmksh和所做的,但它们bash处理的信号列表在这三个实现之间是不同的。这三个实现之间唯一共同的信号似乎是INTQUIT、和。TERMALRMHUP

如果您希望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在您提到的情况下不会调用陷阱,很明显您正在输入未指定行为。

相关内容