4 ms·
> Don’t forget the set -euo pipefail at the beginning of your script. What does -euo means? I don’t know, I copy-pasted it and man set said there is no manual e
by godshatter 5y ago
> Don’t forget the set -euo pipefail at the beginning of your script. What does -euo means? I don’t know, I copy-pasted it and man set said there is no manual entry for set.
Use "man bash" to find the list of built-in commands. Scroll way down, or search for "SHELL BUILTIN COMMANDS".
The "e" command-line switch to the set command tells the script to exit immediately if there is a non-zero return value. The "u" switch tells the shell to treat unset variables as errors when performing parameter expansion. The "o" switch enables the following option (in this case "pipefail"). "pipefail" tells the script to return the value of the rightmost command that returned with a non-zero value in a pipeline. This is all paraphrased, the details are in the man page.
- ajkjk 5y agoIt's kinda nonsense that `man set` doesn't provide that information. But it's kinda nonsense that those flags aren't the default, anyway.
- aidenn0 5y ago"man set" can't provide that information trivially without knowing your shell; dash/bash/ksh/zsh will all be subtly different. However, if you are running bash, "help set" is fine. FWIW, I really don't like pipefail as a default (e.g. piping to "head" causes random pipefails) and -e also has some confusing semantics. Also either failglob or nullglob are more important than either and -C is useful for some scripts as well. [edit] Simple example of confusing "set -e" semantics: The following does not print "hi" and shows returns error status, as expected: (set -e; echo hi); echo $? But put it in an if statement, and it's suddenly success, and does print hi: if (set -e; false; echo hi); then echo hello; fi The same problem applies to functions. The below function will remove all files in the current directory if it's called from a conditional, but not otherwise! foo() { set -e cd /some_directory # set -e means we exit if this fails rm -rf * } I think just defining a die() function and using it after any command that must succeed is more verbose, but less error prone: cd /some_directory || die "chdir failed" rm -rf *
- drran 5y ago> (set -e; echo hi); echo $? It works in my shell. :-/ It looks like you forgot to insert `false` command. You are pointing to the problem with -e not working in subshell/deep functions, because of POSIX. Right? It's described in bash documentation: http://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html http://www.gnu.org/software/bash/manual/html_node/The-Set-Bu... > I think just defining a die() function and using it after any command that must succeed is more verbose, but less error prone: Yep. It's the style I developed 12 years ago, when working at Bazaarvoice, when I was lead of devops team. I created the whole library for bash, to use this pattern consistently. See https://github.com/vlisivka/bash-modules#error-handling https://github.com/vlisivka/bash-modules#error-handling
- ebeip90 5y agoIf you're using ZSH, this will give you a Python-style backtrace showing the specific line of each failure, even with nested function calls. https://gist.github.com/zachriggle/8574964d2e3078cdfae84b5744a9d4dc https://gist.github.com/zachriggle/8574964d2e3078cdfae84b574... e.g. An error occurred on ./test:18 Frame 1 (./test:21) 18 false 19 } 20 21 >>> a Frame 2 (./test:6) 3 source TRAPERR.zsh 4 5 a() { 6 >>> b 7 } 8 9 b() { Frame 3 (./test:10) 7 } 8 9 b() { 10 >>> c 11 } 12 13 c() { Frame 4 (./test:14) 11 } 12 13 c() { 14 >>> d 15 } 16 17 d() { Frame 5 (./test:18) 15 } 16 17 d() { 18 >>> false 19 } 20 21 a
- drran 5y agoI can do this in bash too (partially), with `set -eE` and bash-modules: #!/bin/bash . import.sh strict log a() { b } b() { c } c() { d } d() { false } a Result: $ ./test.sh [test.sh] PANIC: Uncaught error. at d(./test.sh:13) at c(./test.sh:10) at b(./test.sh:7) at a(./test.sh:4) at main(./test.sh:16) However, it stops to work at some point, e.g. in `for` loop, or in a subshell. zsh is better in this regard.
- AceJohnny2 5y agoOff-topic, but Bash's manpage is awful and a great demonstration of the limitation of manpages. Not that the content is bad (it's great!), but as OP (and you) demonstrated, finding relevant information is close to impossible in the humongous document. In Bash's defense, its manpage is a concession to people's habits, and its documentation really rests in its Info page. Except that doesn't seem to be popular either (I'll admit to being still inexperienced with its UI, after decades of sparse usage)...
- AceJohnny2 5y agoPerl (and Git and TCL) seem to have found a middle ground, where they broke up their manpages into different ones that refer to each other (via "SEE ALSO" section at the bottom). But it's sad that, in 2021, we still have such a poor terminal documentation system, and the improvement invented 40 years ago (Info) gained no steam...
- godshatter 5y agoI always forget about the info command, even though it's mentioned in most man pages. So I typed "info bash", and went looking for the "set" command with my almost null knowledge of the info command. It took me a while, but I eventually found it's description under indexes/built-in index/set. It was surprisingly more difficult to find than just looking in the man page, but did take me much less time since I didn't need to skim the whole document to find it. Typing "info info" was actually really helpful, though. Info has a lot more power than I knew about. Typing "i set" while in info brought me right to the set command description. Guess I should learn the tools a bit better.
- massysett 5y agoContrary to typical GNU practice, the bash info manual states that it is intended as a “ brief introduction” and that the man page is the definitive reference on shell behavior: https://www.gnu.org/software/bash/manual/html_node/index.html https://www.gnu.org/software/bash/manual/html_node/index.htm...
- AceJohnny2 5y ago