20

I am using set -e to stop execution of a script on first error.

The problem is that this does not tell me what went wrong.

How can update a bash script so it will display me the last command that failed?

sorin
  • 161,544
  • 178
  • 535
  • 806

5 Answers5

22

Instead of set -e, use an ERR trap; you can pass $BASH_LINENO in to get the specific line number on which the error occurred. I provide a script taking advantage of this in my answer at https://stackoverflow.com/a/185900/14122

To summarize:

error() {
   local sourcefile=$1
   local lineno=$2
   # ...logic for reporting an error at line $lineno
   #    of file $sourcefile goes here...
}
trap 'error "${BASH_SOURCE}" "${LINENO}"' ERR
Community
  • 1
  • 1
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • 2
    You can also use both `set -e` and the ERR trap together, if you want your script to exit after calling the trap function, or you can call `exit` explicitly in the trap function when you want that to happen. – Keegan Quinn Aug 14 '12 at 19:18
  • 1
    any idea how to make it handle unbound variables `set -u;echo $str` ? – Aquarius Power Jul 25 '14 at 02:54
  • Works great in our works bash library! No more digging to see what command failed. – evo_rob Jan 26 '16 at 11:41
  • 3
    Very nice! In case you wanted to use this mechanism here and there in your scripts without using a shared lib with this `error` function, I'd recommend to just add this line (while `#!/bin/bash -e` or `set -e` is on): `trap 'echo "[ERROR] Error occurred at $BASH_SOURCE:$LINENO command: $BASH_COMMAND"' ERR` .. This would also print the command that caused the failure. – Stepan Vavra Feb 15 '17 at 13:11
5
  1. make err.sh

    set -e
    trap 'echo "ERROR: $BASH_SOURCE:$LINENO $BASH_COMMAND" >&2' ERR
    
  2. include it (. err.sh) in all your scripts.

  3. replace any

    ... | while read X ; do ... ; done

    with

    while read X ; do ... ; done < <( ... )

    in your scripts for the trap to give the correct line number/command in the error message

user1133275
  • 2,642
  • 27
  • 31
1

Have you tried with --verbose?

bash --verbose script.sh
dschulz
  • 4,666
  • 1
  • 31
  • 31
1

You can't use set -e by itself because processing will immediately stop after any error. Take a look at the Set Builtin section of the Bash Reference Manual for more information about the -x and -v options, which you can use for debugging.

Something like:

set -e
set -v

will exit on any error, while showing you each input line as it is read. It will not, however, show you just the line with the error. For that, you will need to do your own explicit error checking.

For example:

set +e
if false; then
    real_exit_status=$?
    echo 'Some useful error message.' >&2
    exit $real_exit_status
fi
Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199
0

set -ex will show (all) lines as they are executed and stop at the first command returning nonzero (not as part of if/while/until constructs).

Jens
  • 69,818
  • 15
  • 125
  • 179