Skip to content
shellhacks.dev
Debugging

Stop on the first error and show where

Report where a script failed with trap '...' ERR and set -E. LINENO gives the line, BASH_COMMAND the command and $? the status, even inside functions.

1 min read
Summarize in AI

A script with set -e stops with no message, and you cannot tell which of two hundred lines was the failing one.

Shell
set -eE
trap 'echo "failed at line $LINENO: $BASH_COMMAND (status $?)" >&2' ERR
list_missing() {
  ls /nonexistent-dir
}
echo start
list_missing
echo never reached
Text
start
ls: cannot access '/nonexistent-dir': No such file or directory
failed at line 4: ls /nonexistent-dir (status 2)

The ERR trap runs when a command fails, in the context where it failed. LINENO is the line number there, BASH_COMMAND holds the command that was running and $? is its status, all described in the Bash manual. Without -E, also written errtrace, the trap is not inherited by functions, command substitutions and subshells, so a failure inside list_missing would produce nothing. With set -e the script then exits.

The trap does not fire for a failure inside an if condition, a && or || list, or a ! command, since those are checks made on purpose. In Bash 5 LINENO inside a trap string is correct, and it was unreliable in some older releases. The trap reports one frame; the next snippet adds the call chain.

Share

More snippets

Debugging

Print each line as it is read

Print every script line as the shell reads it, before expansion, with set -v. Pair it with set -x to see the source line and the expanded command.

1 min read
Debugging

Trace only part of a script

Trace only the lines you are debugging by wrapping them in set -x and set +x. Write { set +x; } 2>/dev/null so the switch-off command is not traced itself.

1 min read

Get new posts by email

One email when a new post is published. No spam.

Unsubscribe in one click. No spam, ever.