Where is the exit status after trap / return?

I was playing using trap inside a function because of this question and came up with this minor question. Given the following code:

 d() { trap 'return' ERR false echo hi } 

If I run d , trap causes the shell to return from the function without printing hi. So far, so good. But if I run it a second time, I get a message from the shell:

- bash: return: can only "return" from a function or script source

At first, I suggested that this meant that the ERR sigle occurred twice: once when false gave a non-zero exit status (inside the function) and again when the function itself returned with a non-zero exit status (outside the function). But this hypothesis does not pass this test:

 e() { trap 'echo +;return' ERR false echo hi } 

If I run above, no matter how often I run it, I can no longer only get return from a function or source of a warning script from bash. Why does the shell consider a compound command other than a simple command in trap arg?

My goal was to maintain the actual exit status of the command that caused the function to exit, but I think that everything that causes the above behavior also makes it harder to capture exit status:

 f() { trap ' local s=$? echo $s return $s' ERR false echo hi } bash> f; echo $? 1 0 

Wat? Can someone explain why $s expands to two different values โ€‹โ€‹here, and if that turns out to be the same reason, the aforementioned differentiation between return and echo +; return echo +; return ?

+5
source share
1 answer

Your first conclusion was right: the ERR signal occurred twice.

During the first execution of 'd', you define a trap globally. This affects the following commands (the current call to d has no effect). During the second execution of "d", you again define the trap (not very useful), calling "false" fails, so we execute the handler defined by the trap. Then we return to the parent shell, where the "d" also fails, so we again run the trap.

Just a comment. ERR can be given as an argument to "sigspec", but ERR is not a signal ;-) From the BASH manual:

 If a sigspec is ERR, the command arg is executed whenever a simโ€ ple command has a non-zero exit status, subject to the following conditions. [...] These are the same conditions obeyed by the errexit option. 

Using the 'e' function, the ERR handler executes the echo command, which succeeds. Therefore, the function "e" is not interrupted, therefore, in this case, the ERR handler is not called twice.

If you try "e; echo $?" you will read "0".

Then I tried your function 'f'. I observed the same behavior (and I was surprised). The reason is NOT the bad value of $ s. If you try to make a hardcode value, you should notice that the argument passed to the return statement is ignored when it is executed by the trap handler.

I donโ€™t know if the normal behavior is or if it is a BASH error ... Or maybe a trick to avoid an infinite loop in the interpreter :-)

By the way, this is a bad use of the trap, in my opinion. We can avoid the side effect of the trap by creating a sub-shell. In this case, we avoid the error in the parent shell, and we save the exit code of the internal function:

 g() ( trap 'return' ERR false echo hi ) 
+3
source

Source: https://habr.com/ru/post/969696/


All Articles