TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Why doesn't Bash’s ‘set -e’ do what I expected? (2021)

176 pointsby gurjeetover 2 years ago

27 comments

drothlisover 2 years ago
A lot of commenters suggesting &quot;pipefail&quot; aren&#x27;t realising the full extent of the problem. Here&#x27;s an example that might be clearer, from <a href="https:&#x2F;&#x2F;david.rothlis.net&#x2F;shell-set-e" rel="nofollow">https:&#x2F;&#x2F;david.rothlis.net&#x2F;shell-set-e</a><p>This prints “a”, as you’d expect:<p><pre><code> set -e myfun() { printf a; false; printf b; } myfun printf c </code></pre> ...because the “set -e” terminates the whole script immediately after running the “false” command.<p>But this script prints “a-b-True”, where some people (myself included) might have expected it to print “a-False”:<p><pre><code> set -e myfun() { printf a-; false; printf b-; } if myfun; then printf True else printf False fi </code></pre> The “set -e” is ignored completely. Putting another “set -e” inside the definition of myfun doesn’t make any difference.
评论 #33122071 未加载
评论 #33122256 未加载
评论 #33121055 未加载
评论 #33125237 未加载
ziotom78over 2 years ago
In the 2000s, I was running extensive sets of simulations and data reduction scripts for a scientific experiment, and I was heavy relying on scripts to run the programs, collect the results, and distribute them over several servers. At first I developed those scripts using bash, but I needed to do math and complex iterations over file names and different parameter files, and I continuously stumbled upon weird behaviors and had to rely to hard-to-understand quirks like the ones explained in the article (which bit me more than once!).<p>After a while I stumbled upon scsh [1], which at first didn&#x27;t impress me because I ran it as an interactive shell, and from this point of view it was really ugly. But then I realized that scsh was primarily meant as a way to run shell <i>scripts</i>, and I immediately felt in love. I had the power of a Scheme interpreter, the ability to easily use mathematical expressions (the awesomeness of Scheme&#x27;s numerical tower!) and macros, and a very effective way to redirect inputs and outputs and pipe commands that was embedded in the language [2]!<p>In those years I used scsh a lot and developed quite complex scripts using it, it was really a godsend. Unfortunately the program got abandoned around 2006 because it was not trivial to add support for 64-bit architectures. However, while writing this post I&#x27;ve just discovered that somebody has revived the project and enabled 64-bit compilation [3]. I would love to see a revamp! Nowadays I use Python for complex scripts, but it&#x27;s not the same as a language with native support for redirection and pipes!<p>[1] <a href="https:&#x2F;&#x2F;scsh.net&#x2F;" rel="nofollow">https:&#x2F;&#x2F;scsh.net&#x2F;</a><p>[2] <a href="https:&#x2F;&#x2F;scsh.net&#x2F;docu&#x2F;html&#x2F;man-Z-H-3.html#node_chap_2" rel="nofollow">https:&#x2F;&#x2F;scsh.net&#x2F;docu&#x2F;html&#x2F;man-Z-H-3.html#node_chap_2</a><p>[3] <a href="https:&#x2F;&#x2F;github.com&#x2F;scheme&#x2F;scsh" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;scheme&#x2F;scsh</a>
评论 #33118357 未加载
评论 #33118162 未加载
评论 #33118815 未加载
评论 #33122756 未加载
评论 #33118117 未加载
评论 #33122188 未加载
评论 #33119850 未加载
chubotover 2 years ago
All of these problems are fixed in OSH.<p>It runs your bash scripts but you can also opt into correct error handling. The simple invariant is that it doesn&#x27;t lose an exit code, and non-zero is fatal by default.<p>See <a href="https:&#x2F;&#x2F;www.oilshell.org&#x2F;release&#x2F;latest&#x2F;doc&#x2F;error-handling.html" rel="nofollow">https:&#x2F;&#x2F;www.oilshell.org&#x2F;release&#x2F;latest&#x2F;doc&#x2F;error-handling.h...</a><p><i>Oil 0.10.0 - Can Unix Shell Error Handling Be Fixed Once and For All?</i><p><a href="https:&#x2F;&#x2F;www.oilshell.org&#x2F;blog&#x2F;2022&#x2F;05&#x2F;release-0.10.0.html" rel="nofollow">https:&#x2F;&#x2F;www.oilshell.org&#x2F;blog&#x2F;2022&#x2F;05&#x2F;release-0.10.0.html</a><p>This took quite awhile, and I became aware of more error handling gotchas than I knew about when starting the project:<p>e.g. it&#x27;s impossible in bash to even see the error status of a process sub like diff &lt;(sort left.txt) &lt;(sort OOPS)<p>If you have bash scripts that you don&#x27;t want to rewrite, try<p>1) run them with OSH<p>2) Add shopt --set oil:upgrade at the top to get the error handling fixes.<p>Tell me what happens :) <a href="https:&#x2F;&#x2F;github.com&#x2F;oilshell&#x2F;oil" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;oilshell&#x2F;oil</a><p>I spent a long time on that, but the post didn&#x27;t get read much. I think it&#x27;s because it takes a lot of bash experience to even understand what the problem is.<p>(rehash of <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=33075915" rel="nofollow">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=33075915</a> which came up the other day :) )
评论 #33117609 未加载
评论 #33122521 未加载
kazinatorover 2 years ago
Mainly, the reason why Bash&#x27;s &quot;set -e&quot; doesn&#x27;t do what you expected is this.<p>set -e comes from the POSIX shell language, descended from the Bourne Shell.<p>The examples you&#x27;re using use obscure Bash features. For instance let turns an arithmetic result into a termination status, where 0 is fail (opposite to the POSIX convention and all).<p>set -e works to the extent that your commands have a sane termination status, which they generally do if they are standard built-ins or well-behaved utilities.<p>One Bash feature improves the effectiveness of set -e (or exit status testing in general). In a command pipe:<p><pre><code> a | b | .. | z </code></pre> the termination status is obtained from z. That&#x27;s standard. If z indicates success, the pipeline is successful no matter how a through y terminate. Bash has a &quot;pipefail&quot; option to help with this.
评论 #33118188 未加载
woudsmaover 2 years ago
I can highly recommend using Shellcheck [0] when writing Bash, it also has extensions for VS Code and other IDE&#x27;s. It makes writing Bash much easier.<p>[0] <a href="https:&#x2F;&#x2F;github.com&#x2F;koalaman&#x2F;shellcheck" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;koalaman&#x2F;shellcheck</a>
评论 #33119965 未加载
评论 #33119927 未加载
NackerHughesover 2 years ago
Short answer: because it&#x27;s Bash. <i>No</i> syntax or language construct will do what you expected.
评论 #33119457 未加载
评论 #33118946 未加载
评论 #33118251 未加载
strkenover 2 years ago
You don&#x27;t have to be hyper-aware of false positives with &quot;set -euo pipefail&quot;. False positives bring themselves to your attention during testing, while false negatives don&#x27;t announce themselves at all. It&#x27;s almost always preferable for your code to incorrectly fail and force you to stick &quot;|| true&quot; on the end, than to incorrectly succeed and let you miss the bug.
评论 #33118137 未加载
ohiovrover 2 years ago
All set -e does is halt further execution of your script if any line exits above 0. There is really nothing bash can do about this. It can&#x27;t perform a psychological evaluation on why a program is not giving the expected output. And most of the time, when something fails, if it were made by a less than serious programmer (like myself) they don&#x27;t bother to exit on error correctly with a code above zero. But if you are building a script collection, or python utility or even an binary, simply exit 1 if you encounter a general error. Then further up the chain in your shell scripts the error can be handled properly. There are more specific error codes you can use that might be helpful to your shell script.<p>If you are wondering what in the world I&#x27;m talking about and I&#x27;ve missed your question entirely, sorry about that. My feet are tired.
评论 #33116968 未加载
评论 #33116971 未加载
评论 #33116859 未加载
评论 #33117016 未加载
评论 #33117049 未加载
pizza234over 2 years ago
Shell scripts can be thought like C++. They can be sanely managed only if one adopts a strict subset of functionalities.<p>The page is probably oriented at situations where one needs to support any version of bash and any obscure&#x2F;inadvisable functionality (mind that there are still devs that mix sh and bash syntax in the same script), which is very inconvenient and error prone, so manual error handling <i>may</i> make sense.<p>While there is always something insane behind the corner in Bash, with a restricted subdomain (e.g. bash 4.2+, strict shell options, and shellcheck) it&#x27;s possible to progressively write reasonably solid shell scripts.<p>The document conclusion is somewhat biased. &quot;to handle errors properly&quot; implies that `-e` in inherently unreliable, which not fair - strict shell options do remove certain classes of errors, which doesn&#x27;t hurt.
评论 #33119779 未加载
gurjeetover 2 years ago
Also noteworthy, this post of mine with authoritative text from GNU docs. Read &quot;(Un)Portable Shell Programming&quot;<p><a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=31678176" rel="nofollow">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=31678176</a>
评论 #33116632 未加载
jasonhanselover 2 years ago
Annoyingly, when a process is terminated by an unhandled signal (say, SIGTERM), it is treated as if it exited with a nonzero exit code. This can make it tricky to use non-builtin commands as conditions in &quot;if&quot; statements, since there&#x27;s always the potential edge case where the &quot;if&quot; block is skipped because of a signal that the condition received.
thomashabets2over 2 years ago
Because bash error handling is a thousand blades and no handle.<p><a href="https:&#x2F;&#x2F;blog.habets.se&#x2F;2021&#x2F;06&#x2F;The-uselessness-of-bash.html" rel="nofollow">https:&#x2F;&#x2F;blog.habets.se&#x2F;2021&#x2F;06&#x2F;The-uselessness-of-bash.html</a><p>I&#x27;ve reviewed a lot of code, bash and otherwise. I have never, not once, reviewed bash code that didn&#x27;t have subtle bugs. And this is code written by smart people.
评论 #33119833 未加载
TheAdamistover 2 years ago
If you modify your PS1 to include $? It makes writing shell scripts that rely on exit codes a lot easier. It should be the default in my opinion.<p>Build scripts that fail and return 0 are my nemesis.
评论 #33117204 未加载
oftheoaksover 2 years ago
This is really interesting. The case pointed out in Ex.3 is pretty hilarious:<p>(from the bash manual)<p><pre><code> The ERR trap [same rules as set -e] is not executed if the failed command is part of the command list immediately following a while or until keyword, part of the test in an if statement, part of a command executed in a &amp;&amp; or || list except the command following the final &amp;&amp; or || [...]</code></pre>
the_dukeover 2 years ago
I use &quot;set -Eeuo pipefail&quot; in pretty much all bash scripts. (and often -x as well)<p>Makes things much saner.<p>This post is a better introduction than the submission: <a href="https:&#x2F;&#x2F;vaneyckt.io&#x2F;posts&#x2F;safer_bash_scripts_with_set_euxo_pipefail&#x2F;" rel="nofollow">https:&#x2F;&#x2F;vaneyckt.io&#x2F;posts&#x2F;safer_bash_scripts_with_set_euxo_p...</a>
评论 #33118709 未加载
ilyashover 2 years ago
One of the reasons I created Next Generation Shell. It has exceptions. So &quot;if $(grep ...)&quot; works correctly as opposed to bash. grep exit codes: 0 - found, 1 - not found, 2 - error. bash can not handle this correctly in if. There are just two branches for 3 exit codes. NGS has two branches and exception that can be thrown. Yep, every single &quot;if grep ...&quot; in bash is a bomb.
shp0ngleover 2 years ago
The article is great, but I wholly disagree with the conclusion “don’t use -e”.<p>It’s still much better to use it than not to use it.
cassepipeover 2 years ago
I am using zsh but only because it comes with a little more out the box and because zle&#x27;s excellent vi mode (supports text objects for the win)<p>But I am wondering, does zsh fare better when it comes to writing more correct scripts or is it plagued with the same issues ?
teo_zeroover 2 years ago
Few people understand that if...then in bash is actually a form of try...catch.<p>The -e terminates the script at every failure not caught by a try...catch.<p>With this in mind, it&#x27;s easier to predict bash&#x27;s behavior.
wkdneidbwfover 2 years ago
mountain out of a molehill imo. there’s a certain point where you’ll be fighting shell more than it’s helping—choosing another language is the better choice. i’m not a wizard but i feel like i’ve developed a decent intuition for what’s sane to do in shell and what needs something else.<p>and even then, shelling out from another language when absolutely necessary can be a better option
agumonkeyover 2 years ago
What&#x27;s the best and smallest choice to replace admin&#x2F;ops bash scripts ? Python ? Python with some lib ? Ruby ? Lua ? Rust ?
评论 #33120039 未加载
Maursaultover 2 years ago
If anyone reading these threads is over 70yo, please reply to this comment with the correct explanation.
junonover 2 years ago
<p><pre><code> set -euo pipefail </code></pre> This is how all of my shell scripts start.
评论 #33121752 未加载
planedeover 2 years ago
the `read -r foo &lt; configfile` might be obscure, but every line in a POSIX text file ought to have a newline terminator. If this is worth erroring out on probably depends on context.
trashtesterover 2 years ago
In your bash shell, type:<p>set -e<p>let 1<p>let 0
zgsover 2 years ago
Because you don&#x27;t understand what it is meant to do.
pcthrowawayover 2 years ago
I&#x27;m not sure what this person <i>did</i> expect. That bash magically parsed the output and memory of running programs, and read the user&#x27;s thoughts, to determine if the state of the program indicates a condition that the user would consider an error?<p>set -e does exactly what you&#x27;d expect, arguably, with the exception of subshells and conditions.<p>And those rules are extremely simple to learn too. If you understand when a statement which might be composed of other statements would have an error, you can predict what set -e will do
评论 #33117124 未加载