这是一个简单的脚本,它在当前目录中设置一个临时目录,并设置一个陷阱以在退出时将其删除。
#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
在您提到的情况下不会调用陷阱,很明显您正在输入未指定行为。