when wiring bash scripts i always use set -eu -o pipefail
to make sure any error that's not explicitly handled is a hard fault. sometimes it's however hard to find the exact line, thus i usually just preemptively add set -x
at the beginning, so that in case sth fails, i have a full context. it works, but it's clearly ugly.
there's however a much nicer way of handling it – with trap
s.
let's take a sample starting code:
#!/bin/bash set -eu -o pipefail echo "hello, world" date false "this is where we'll fail" echo "never see me"
the output is enigmatic:
hello, world Thu Oct 3 20:30:05 CEST 2024
we never made it to the end. in shell $?
is 1
, so the error is reported, but in a longer script – good luck finding what exactly failed!
here's how to do this in a better way:
#!/bin/bash set -eu -o pipefail on_error() { echo "ERROR: $0:$BASH_LINENO failed with exit code $? on:" >&2 echo " $BASH_COMMAND" >&2 } trap on_error ERR # actual script goes here - same as before: echo "hello, world" date false "this is where we'll fail" echo "never see me"
and now the output is decodable, indeed:
hello, world Thu Oct 3 20:32:03 CEST 2024 ERROR: ./my_script:14 failed with exit code 1 on: false "this is where we'll fail"
now we get both nice output and a foot in the door, when things fail. it's such a nice, simple feature – no idea why it's not a common thing all over the place.