我在bash中看到一些奇怪的行为,并在子shell中捕获EXIT
。我希望以下四行都输出相同的东西(“喜被困”):
a=$(trap 'echo trapped' EXIT ; echo hi); echo $a
a=$(trap 'echo trapped' EXIT && echo hi); echo $a
a=$(trap 'echo trapped' EXIT ; /bin/echo hi); echo $a
a=$(trap 'echo trapped' EXIT && /bin/echo hi); echo $a
前三个打印“喜被困”,但不是最后一个。它只输出“hi”。没有调用陷阱。您可以使用set -x
验证这一点:
set -x; a=$(trap 'echo trapped' EXIT ; echo hi); set +x; echo $a
set -x; a=$(trap 'echo trapped' EXIT && echo hi); set +x; echo $a
set -x; a=$(trap 'echo trapped' EXIT ; /bin/echo hi); set +x; echo $a
set -x; a=$(trap 'echo trapped' EXIT && /bin/echo hi); set +x; echo $a
通过一些反复试验,我发现在以下情况下未调用EXIT
陷阱:
&&
链接在一起的命令列表。
;
甚至||
,则会执行陷阱。作为参考,我偶然发现了这一点,因为rvm使用自己的函数覆盖cd
,最终在EXIT
上添加了一个陷阱(其中包括)echo -n 'Saving session...'
。我正在运行uses this bash idiom:
some_dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )
所以some_dir
附加了“保存会话...”。它很难调试,因为子shell并不总是运行rvm添加的EXIT
陷阱。
答案 0 :(得分:0)
我使用strace -e clone,execve -f -p $$&
来查看运行回显版本和/ bin / echo版本时当前shell的行为。我放置了&
,以便它将继续读取命令。
在/ bin / echo版本中,我相信bash做了一个快捷方式并执行了/ bin / echo的()子外壳,因此陷阱不再存在(我想陷阱无法在execve中生存)。 / p>
在裸回显版本中,它是内置的shell,因此无需执行,因此,当前()子shell作为shell退出,并调用trap。
现在,另一件事很奇怪,如果我这样做:bash -c 'a=$(trap "echo trapped" EXIT && /bin/echo hi); echo $a'
,您会看到它被困了!
我猜这是因为bash仅在交互模式下才执行快捷键。批处理模式和交互模式之间的另一个示例差异是for x in $(seq 1 30); sleep 1; done
。如果您在终端中输入它,然后立即按C-z,然后使用fg
将其恢复,您将看到它会立即退出-其余的睡眠将被跳过。如果将其放在脚本中,然后将C-z,fg放入脚本中,则它将在其余循环中继续休眠。