3 ms·
I was a bash sympathizer until a post made the rounds about how, even if you `set -euxo pipefail`, `declare x="$(err)"` will silently eat the return code of the
by LanternLight83 4y ago
I was a bash sympathizer until a post made the rounds about how, even if you `set -euxo pipefail`, `declare x="$(err)"` will silently eat the return code of the subshell. This applies to `local` too, and tbf is mentioned somewhat offhandedly on some man page, but was the straw that solidified my opinion. There's just no reasonable way that even an experienced user of Bash (ie. the kinds of folks who think that set command has them covered) could be expected to know about this footgun. The solution is to always declare and assign variables separately. Still use it all the time, and I guess "now I know", but, wtf Bash. Safety options are poorly bolted on.
- ryapric 4y agoI don't think you can capture/handle exit codes of subshells anyway, right? I've been operating under that assumption for years, and just don't do subshells if I can avoid them.
- 0xbadcafebee 4y ago$? contains the return status for subshells, commands, pipelines, functions, etc. From the man page, under Special Parameters : ? Expands to the exit status of the most recently executed foreground pipeline. $ foo="$(echo foobar ; exit 3)" ; ret=$? ; echo "output: $foo" ; echo "return status: $ret" output: foobar return status: 3 Also, PIPESTATUS is an array with the return status from each command in a pipeline.
- chubot 4y agoI agree, and that was out of the motivations for https://www.oilshell.org/ https://www.oilshell.org/ It runs your bash scripts but you can also opt into correct error handling. The simple invariant is that it doesn't lose an exit code, and non-zero is fatal by default. Oil 0.10.0 - Can Unix Shell Error Handling Be Fixed Once and For All? https://www.oilshell.org/blog/2022/05/release-0.10.0.html https://www.oilshell.org/blog/2022/05/release-0.10.0.html This took quite awhile, and I became aware of more error handling gotchas than I knew about when starting the project: https://www.oilshell.org/release/latest/doc/error-handling.html https://www.oilshell.org/release/latest/doc/error-handling.h... e.g. it's impossible in bash to even see the error status of a process sub like diff <(sort left.txt) <(sort OOPS) If you have bash scripts that you don't want to rewrite, try 1) run them with OSH 2) Add shopt --set oil:upgrade at the top to get the error handling fixes. Tell me what happens :) https://github.com/oilshell/oil https://github.com/oilshell/oil I spent a long time on that, but the post didn't get read much. I think it's because it takes a lot of bash experience to even understand what the problem is.
- riffraff 4y ago> Add shopt --set oil:upgrade at the top to get the error handling fixes How does this work? It seems magic
- chubot 4y agoRight now there are 22 options that form the fixes and enhancements to bash: oil$ shopt -p oil:upgrade shopt -s command_sub_errexit shopt -u dashglob shopt -s errexit shopt -u expand_aliases shopt -s inherit_errexit ... Some affect parsing and some affect execution. OSH is a bash-compatible shell, from scratch! :) Let me know what happens
- 0xbadcafebee 4y agoShellcheck warns you about it: $ cat foo.sh #!/usr/bin/env bash set -euxo pipefail declare x="$(err)" $ shellcheck foo.sh In foo.sh line 3: declare x="$(err)" ^-- SC2034 (warning): x appears unused. Verify use (or export if used externally). ^-- SC2155 (warning): Declare and assign separately to avoid masking return values. For more information: https://www.shellcheck.net/wiki/SC2034 -- x appears unused. Verify use (or ... https://www.shellcheck.net/wiki/SC2155 -- Declare and assign separately to ... And the Bash man page mentions it a couple times, particularly around Pipelines, pipefail, Lists, and Compound Commands. You can also check exit status in the PIPESTATUS array. I almost never use set -o pipefail, and often not even set -e. Your scripts end up failing for mysterious reasons and it takes forever to figure out which part of which pipeline failed. Instead, I simply check the result of the end of the pipe (did it return any data? does it look valid?) and that is good enough 99% of the time.