5 ms·
A lot of commenters suggesting "pipefail" aren't realising the full extent of the problem. Here's an example that might be clearer, from https://david.rothlis.n
by drothlis 4y ago
A lot of commenters suggesting "pipefail" aren't realising the full extent of the problem. Here's an example that might be clearer, from https://david.rothlis.net/shell-set-e https://david.rothlis.net/shell-set-e
This prints “a”, as you’d expect:
set -e
myfun() { printf a; false; printf b; }
myfun
printf c
...because the “set -e” terminates the whole script immediately after running the “false” command.
But this script prints “a-b-True”, where some people (myself included) might have expected it to print “a-False”:
set -e
myfun() { printf a-; false; printf b-; }
if myfun; then
printf True
else
printf False
fi
The “set -e” is ignored completely. Putting another “set -e” inside the definition of myfun doesn’t make any difference.
- deleted 4y ago[deleted]
- jlokier 4y agoIt's always been odd that Bash has hundreds of options for controlling its behaviour in non-standard ways, via "set", "shopt" and environment variables, but it's never had an option to make "-e" do the obviously natural behaviour,, I encountered the "you can't enable -e" problem years ago in a complex build system that used Bash to build embedded sysem components. The scripts were all designed on the assumption that "set -eu -o pipefail" would cause early exit on any failing commands as if doing the equivalent of "exit $?" or "return $?", and of course it is not reliable, as your example shows. The very surprising behaviour of "set -e" inside functions was not noticed for a long time while the system was being written and used. When it was noticed, "set -e" was added inside the functions because that seemed to work for the Bash version at the time, then later it stopped working.
- chubot 4y agoit's never had an option to make "-e" do the obviously natural behaviour,, This is harder than it sounds! :) There's arguably not a natural behavior for shell, because $? is overloaded in Unix. It can mean success/failure or it can mean true/false/error. https://www.oilshell.org/release/latest/doc/error-handling.html#what-does-mean https://www.oilshell.org/release/latest/doc/error-handling.h... Oil introduces some new idioms that led you distinguish between the two paradigms, so it's best to change the way you write scripts. It's not something bash can magically fix. https://www.oilshell.org/release/latest/doc/idioms.html#error-handling https://www.oilshell.org/release/latest/doc/idioms.html#erro... That said, just running your scripts with Oil will flag problems, acting like a ShellCheck at runtime, catching things that ShellCheck can't. See the sibling reply for a demo, and this comment: https://news.ycombinator.com/item?id=33117337 https://news.ycombinator.com/item?id=33117337
- chubot 4y agoI call this the "disabled errexit quirk" which leads to the "if myfunc" pitfall: https://www.oilshell.org/release/latest/doc/error-handling.html#design-mistake-the-disabled-errexit-quirk https://www.oilshell.org/release/latest/doc/error-handling.h... Here's a demo of how Oil fixes it, which I mentioned in this thread: $ osh hn.sh a-b-True You can add shopt --set strict_errexit at the top of your script: $ osh -o strict_errexit hn.sh if myfun; then ^~ hn.sh:3: errexit was disabled for this construct if myfun; then ^~~~~ hn.sh:3: fatal: Can't run a proc while errexit is disabled. Use 'try' or wrap it in a process with $0 myproc Or just use Oil: $ oil hn.sh <same output> So Oil is acting like a ShellCheck at runtime, to unconditionally flag this error. It cannot be caught using syntax (which ShellCheck is limited to), because function vs. external executable is a runtime decision.
- pizza234 4y agoThis is a separate problem from the pipe one. Anyway, if you're looking that behavior, you need to use `&&` instead of the semicolon.