22

I'm trying to create some error reporting using a Trap to call a function on all errors:

Trap "_func" ERR

Is it possible to get what line the ERR signal was sent from? The shell is bash.

If I do that, I can read and report what command was used and log/perform some actions.

Or maybe I'm going at this all wrong?

I tested with the following:

#!/bin/bash
trap "ECHO $LINENO" ERR

echo hello | grep "asdf"

And $LINENO is returning 2. Not working.

  • You can look at the bash debugger script bashdb. It seems that the first argument to trap can contain variables that are evaluated in the desired context. So trap 'echo $LINENO' ERR' should work. – donothingsuccessfully May 29 '12 at 18:53
  • hmm just tried this with a bad echo | grep command and it returns the line of the Trap statement. But I'll take a look at bashdb – Mechaflash May 29 '12 at 18:56
  • I'm so sorry... I didn't specify in my original question that I need a native solution. I edited the question. – Mechaflash May 29 '12 at 19:05
  • Sorry, I borked the example line: trap 'echo $LINENO' ERR. The first argument to trap is the entire echo $LINENO hardquoted. This is in bash. – donothingsuccessfully May 29 '12 at 19:43
  • 4
    @Mechaflash It would have to be trap 'echo $LINENO' ERR, with single quotes, not double quotes. With the command you wrote, $LINENO is expanded when line 2 is parsed, so the trap is echo 2 (or rather ECHO 2, which would output bash: ECHO: command not found). – Gilles May 29 '12 at 23:56
50

As pointed out in comments, your quoting is wrong. You need single quotes to prevent $LINENO from being expanded when the trap line is first parsed.

This works:

#! /bin/bash

err_report() {
    echo "Error on line $1"
}

trap 'err_report $LINENO' ERR

echo hello | grep foo  # This is line number 9

Running it:

 $ ./test.sh
 Error on line 9
  • thanks for the example with a function call. I didn't know that double quotes expanded the variable in this case. – Mechaflash May 30 '12 at 14:23
  • echo hello | grep foo doesn't seem to throw error for me. Am I misunderstanding something? – geotheory Dec 2 '15 at 22:15
  • @geotheory On my system grep has an exit status of 0 if there was a match, 1 if there was no match and >1 for an error. You can check the behavior on your system with echo hello | grep foo; echo $? – Patrick Dec 7 '15 at 23:17
  • No you're right it is an error :) – geotheory Dec 8 '15 at 9:56
  • Don't you need to use -e on the invocation line, to cause error on command failure? That is: #!/bin/bash -e ? – Tim Bird Mar 31 '17 at 22:39
12

You can also use the bash builtin 'caller':

#!/bin/bash

err_report() {
  echo "errexit on line $(caller)" >&2
}

trap err_report ERR

echo hello | grep foo

it prints filename too:

$ ./test.sh
errexit on line 9 ./test.sh
4

I really like the answer given by @Mat above. Building on this, I wrote a little helper which gives a bit more context for the error:

We can inspect the script for the line which caused the failure:

err() {
    echo "Error occurred:"
    awk 'NR>L-4 && NR<L+4 { printf "%-5d%3s%s\n",NR,(NR==L?">>>":""),$0 }' L=$1 $0
}
trap 'err $LINENO' ERR

Here it is in a small test script:

#!/bin/bash

set -e

err() {
    echo "Error occurred:"
    awk 'NR>L-4 && NR<L+4 { printf "%-5d%3s%s\n",NR,(NR==L?">>>":""),$0 }' L=$1 $0
}
trap 'err $LINENO' ERR

echo one
echo two
echo three
echo four
false
echo five
echo six
echo seven
echo eight

When we run it we get:

$ /tmp/test.sh
one
two
three
four
Error occurred:
12      echo two
13      echo three
14      echo four
15   >>>false
16      echo five
17      echo six
18      echo seven
  • This would be even better using $(caller)'s data to give the context even if the failure is not in the current script but one of its imports. Very nice though! – tricasse Mar 7 at 18:42
2

Inspired by other answer, here's a simpler contextual error handler:

trap '>&2 echo Command failed: $(tail -n+$LINENO $0 | head -n1)' ERR

You can also use awk instead of tail & head if needed.

  • 1
    there's a reason the other answer provides context by way of 3 lines above and 3 lines below the offending line - what if the error emanates from a continuation line? – iruvar Mar 23 at 3:13
  • @iruvar this is understood, but I don't need any of that extra context; one line of context is as simple as it gets, and as sufficient as I need – sanmai Mar 23 at 4:42
  • Ok my friend,+1 – iruvar Mar 23 at 6:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.