Errtrace 和本地

Errtrace 和本地

我正在使用以下脚本:

#!/bin/bash -Eu

trap 'echo Hi' ERR

exit_failure() {
  echo "Hello, World!"
  return 1
}

sub_failure() {
  res=$(exit_failure)
}

sub_failure

其结果如下:

Hi
Hi

但是,如果我更改sub_failure()为以下内容:

sub_failure() {
  local res=$(exit_failure)
}

我没有得到任何输出;ERR不再被困了吗?为什么信号被隐藏了?ERR如果我想使用局部变量,如何捕获?我知道我可以做到local res; res=$(exit_failure),但为什么我必须将两者分开?

答案1

这不是一个错误。这实际上是定义的行为。

使用时bash -Eux您可以看到会发生什么。 (-Eu来自你的shebang + -x

+ trap 'echo Hi' ERR
+ sub_failure
++ exit_failure
++ echo 'Hello, World!'
++ return 1
+++ echo Hi
+ res='Hello, World!
Hi'
++ echo Hi
Hi
++ echo Hi
Hi

当进行命令替换时,trap由于-E切换而被继承。因此,由return 1您的函数触发的继承陷阱中的“Hi”exit_failure()将成为存储在 中的值的一部分ret。 (使用 执行变体时也是如此local

此外,res=...表达式返回1(错误)并触发你的陷阱(在你的sub_failure()函数内部)。

由于res=...return1和函数的结果是函数中最后一个命令的结果,因此结果sub_failure()也是(错误),并且在主 shell 中执行1后会再次触发陷阱。sub_failure因此,您会得到 2 个可见的“Hi”:一个 forres=....和一个 for sub_failure,以及存储在 中的隐藏“Hi” $res

现在来说说local变体:

+ trap 'echo Hi' ERR
+ sub_failure
++ exit_failure
++ echo 'Hello, World!'
++ return 1
+++ echo Hi
+ local 'res=Hello, World!
Hi'

根据定义,在函数中使用时local始终返回。0导致您local res=...评估为0(成功),同时仍然将隐藏的“Hi”存储在$res.因为res=..评估结果0 sub_failure也返回0。所以这一次你获得了一次“隐藏”失败和两次成功。

希望这会有所帮助,即使这个线程很旧;)

也应该清楚为什么要local res=...分裂

local res
res=....

是否恢复第一个变体的行为..? ;)

相关内容