我正在使用以下脚本:
#!/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=....
是否恢复第一个变体的行为..? ;)