Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么bash子shell中的退出陷阱不总是被调用?_Bash_Shell_Rvm - Fatal编程技术网

为什么bash子shell中的退出陷阱不总是被调用?

为什么bash子shell中的退出陷阱不总是被调用?,bash,shell,rvm,Bash,Shell,Rvm,我在bash中看到一些奇怪的行为,并在子shell中捕获EXIT。我希望以下四行都输出相同的内容(“hi-trapped”): 前三个打印“hi-trapped”,但不是最后一个。它只输出“嗨”。陷阱没有被调用。您可以使用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

我在bash中看到一些奇怪的行为,并在子shell中捕获
EXIT
。我希望以下四行都输出相同的内容(“hi-trapped”):

前三个打印“hi-trapped”,但不是最后一个。它只输出“嗨”。陷阱没有被调用。您可以使用
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
陷阱:

  • 整个subshell程序是一个命令列表,这些命令通过
    &&
    链接在一起。
    • 如果您使用
      ,甚至在任何时候,陷阱都会执行
  • 链中的所有命令都必须执行。
    • 如果任何一个命令(最后一个命令除外)以非零退出状态退出,使得最后一个命令永远不会执行,则陷阱将执行
  • 最后一个命令必须是系统上的程序,而不是shell内置命令,也不是函数。
    • 非最终命令可以是内置命令或函数,只要最终命令是程序,陷阱就不会运行
  • 这是故意的吗?有文件记录吗

    作为参考,我遇到这个问题是因为用自己的函数覆盖
    cd
    ,最后在
    EXIT
    上添加了一个陷阱,它(除其他外)
    echo-n“保存会话…”
    。我运行的是一个shell脚本:


    因此,
    some_dir
    得到了附加的“Saving session…”。调试很困难,因为子shell并不总是运行rvm添加的
    EXIT
    陷阱。

    我使用
    strace-e clone,execve-f-p$$&
    来查看当前shell在运行echo版本和/bin/echo版本时正在做什么。我放置了一个
    &
    ,以便它继续读取命令

    在/bin/echo版本中,我相信bash做了一个快捷方式,并为/bin/echo执行了()子shell,因此陷阱不再存在了(我想陷阱在execve中不会存在)

    在bare echo版本中,它是一个内置的shell,因此不需要execve,因此当前()子shell作为shell退出,并调用trap

    现在,另一件奇怪的事情是,如果我这样做:
    bash-c'a=$(trap“echo-trapped”EXIT&&/bin/echo-hi);echo$a'
    ,您将看到它被捕获了


    我猜这是因为bash只在交互模式下进行快捷操作。批处理模式和交互模式之间的另一个示例差异是x的
    (以美元计)(序号130);睡眠1;完成
    。如果您在终端中输入它,并立即按C-z,然后使用
    fg
    将其带回来,您将看到它将立即退出--其余的睡眠将被跳过。如果你把它放在一个脚本中,C-z,fg,它将继续休眠剩下的循环。

    你的观察是正确的,请参阅可能会尝试将stderr也添加到null,
    /dev/null 2>&1
    @Inian,这显然是相关的,但我的场景并不取决于命令的错误状态(或者它们是否符合简单命令的条件),但取决于列表中的最后一个命令是内置/函数还是系统命令。关于重定向stderr。那没用。将
    cd
    重定向到
    /dev/null
    实际上是不必要的,而不是问题的一部分。在所有命令(在
    cd
    之后和
    pwd
    之后)之后运行
    EXIT
    陷阱。这是写给史都的信。所以没有办法避免它。除了关闭stdout,或者在子shell中的最后一个命令之后将stdout重定向到
    /dev/null
    。然而,这仍然不能解释为什么陷阱有时被执行,有时不被执行。
    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
    
    some_dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )