Newlines in ERR trap affect caller 0 line number
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-musl Compiler: gcc Compilation CFLAGS: -g -O2 -Wno-parentheses -Wno-format-security uname output: Linux e4cb51356521 5.11.0-38-generic #42~20.04.1-Ubuntu SMP Tue Sep 28 20:41:07 UTC 2021 x86_64 Linux Machine Type: x86_64-pc-linux-musl Bash Version: 5.1 Patch Level: 8 Release Status: release Description: When an ERR trap includes newlines, the line number returned by "caller 0" is affected. Repeat-By: Here are some examples. $ cat -n 1.bash 1 set -E -e 2 f() { i=0; while caller $((i++)); do :; done; } 3 trap 'f' ERR 4 false $ bash 1.bash 4 main 1.bash $ cat -n 2.bash 1 set -E -e 2 f() { i=0; while caller $((i++)); do :; done; } 3 trap ' 4 f' ERR 5 false $ bash 2.bash 6 main 2.bash $ cat -n 3.bash 1 set -E -e 2 f() { i=0; while caller $((i++)); do :; done; } 3 trap ' 4 5 f' ERR 6 false $ bash 3.bash 8 main 3.bash $ cat -n 4.bash 1 set -E -e 2 f() { i=0; while caller $((i++)); do :; done; } 3 trap 'f' ERR 4 g() { false; } 5 g $ bash 4.bash 4 g 4.bash 5 main 4.bash $ cat -n 5.bash 1 set -E -e 2 f() { i=0; while caller $((i++)); do :; done; } 3 trap ' 4 f' ERR 5 g() { false; } 6 g $ bash 5.bash 6 g 5.bash 6 main 5.bash $ cat -n 6.bash 1 set -E -e 2 f() { i=0; while caller $((i++)); do :; done; } 3 trap ' 4 5 f' ERR 6 g() { false; } 7 g $ bash 6.bash 8 g 6.bash 7 main 6.bash
errexit is not suspended in a pipeline
In the documentation for set -e, the Bash manual says that errexit is suspended in all but the last command of a pipeline: The shell does not exit if the command that fails is part of [...] any command in a pipeline but the last The documentation also of course says that errexit suspension cascades into compound commands: If a compound command or shell function executes in a context where -e is being ignored, none of the commands executed within the compound command or function body will be affected by the -e setting, even if -e is set and a command returns a failure status. This means the following script should output both "1" and "2": (false; echo 1) | cat set -e (false; echo 2) | cat However, it only outputs "1". I tested in Bash 4.0 through 5.2. Is this a bug in the behavior, or is it a bug in the documentation?
Re: errexit is not suspended in a pipeline
On 2023-01-11 06:44, Chet Ramey wrote: On 1/10/23 9:36 PM, Quinn Grier wrote: In the documentation for set -e, the Bash manual says that errexit is suspended in all but the last command of a pipeline: The shell does not exit if the command that fails is part of [...] any command in a pipeline but the last I'm not sure why you included the `part of' in your quote, since it clearly applies to the text following it: "part of the command list immediately following as while or until keyword, part of the test following ..." I agree, my quotation of that documentation is wrong, as "part of" does not apply to "any command in a pipeline". However, I still think my example script shows something fishy. Here's another example script that might help show what I mean. This one goes through all of the apparent contexts where set -e is ignored: # Without set -e, all "echo" commands run. while (false; echo -n 1); do break; done # Outputs 1 until (false; echo -n 2); do break; done # Outputs 2 if (false; echo -n 3); then :; fi# Outputs 3 (false; echo -n 4) && : # Outputs 4 (false; echo -n 5) || : # Outputs 5 (false; echo -n 6) | cat # Outputs 6 ! (false; echo -n 7) # Outputs 7 echo # With set -e, all "echo" commands should still run despite # the fact that "false" would normally cause an exit before # "echo", as these are all contexts where set -e is ignored. set -e while (false; echo -n 1); do break; done # Outputs 1 until (false; echo -n 2); do break; done # Outputs 2 if (false; echo -n 3); then :; fi# Outputs 3 (false; echo -n 4) && : # Outputs 4 (false; echo -n 5) || : # Outputs 5 (false; echo -n 6) | cat # No output (!) ! (false; echo -n 7) # Outputs 7 echo The output of this script is: 1234567 123457 Why is "6" missing from the second line?
Re: errexit is not suspended in a pipeline
On 2023-01-11 13:20, Chet Ramey wrote: They are not all contexts where set -e is ignored. There is a distinction between the effect of -e being ignored and the shell not exiting when a command fails. If you don't like the bash manual page wording, here's what POSIX says: "1.The failure of any individual command in a multi-command pipeline shall not cause the shell to exit. Only the failure of the pipeline itself shall be considered. 2.The -e setting shall be ignored when executing the compound list following the while, until, if, or elif reserved word, a pipeline beginning with the ! reserved word, or any command of an AND-OR list other than the last. 3.If the exit status of a compound command other than a subshell command was the result of a failure while -e was being ignored, then -e shall not apply to this command. I see. I had mistakenly thought that Bash's set -e description was definitively listing the contexts in which set -e is ignored, not just contexts in which set -e may not have the intended effect. Really it's POSIX that definitively lists the contexts in which set -e is ignored, as you explain above. The lists are almost the same, with the only difference being that Bash also lists "any command in a pipeline but the last". This is a context in which set -e is *not* ignored but may also not have the intended effect, as the pipeline ignores the exit statuses of all non-last commands (except if set -o pipefail is being used). Thank you for clearing this up for me.