Não é um bug. Na verdade, é um comportamento definido.
Ao usar bash -Eux
, você pode ver o que acontece. ( -Eu
do seu 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
Ao fazer a substituição do comando, o trap
é herdado por causa da opção -E
. Portanto, o "Hi" da interceptação herdada acionada pela função return 1
de sua função exit_failure()
torna-se parte do valor armazenado em ret
.
(Este também é o caso ao executar a variante usando local
)
Além disso, a expressão res=...
retorna 1
(erro) e aciona sua interceptação (dentro de sua função sub_failure()
).
Como res=...
return 1
e o resultado de uma função é o resultado do último comando na função, o resultado de sub_failure()
também é 1
(error) e seu trap é acionado novamente após sub_failure
foi executado no shell principal. Então você ganha 2 "Hi" s visíveis: um para res=....
e um para sub_failure
e um "Hi" oculto armazenado em $res
.
Agora, para a variante local
:
+ trap 'echo Hi' ERR
+ sub_failure
++ exit_failure
++ echo 'Hello, World!'
++ return 1
+++ echo Hi
+ local 'res=Hello, World!
Hi'
Por definição local
sempre retorna 0
quando usado em uma função. Faz com que seu local res=...
avalie para 0
(sucesso) enquanto ainda tem o "Hi" oculto armazenado em $res
. E como res=..
avalia para 0
sub_failure
, também retorna 0
. Então desta vez você tem uma falha "oculta" e duas vezes sucesso.
Espero que isso ajude mesmo se esse segmento estiver tranquilo;)
E também deve estar claro por que dividir local res=...
em
local res
res=....
restaura o comportamento da primeira variante ..? ;)