10

I have been looking for a way to print the line number inside the shell script when it errors out.

I came across '-x' option, which prints the line when running the shell script, but this is not exactly what I want. Maybe I could do $LINENO before every exit code? Is there a cleaner way to do it?

I just wanted the line number so I could open the shell script and directly go to the place where the interpreter realized the error.

user2441441
  • 1,237
  • 4
  • 24
  • 45

1 Answers1

13

Using

PS4=':$LINENO+'

will add line number to the output of set -x.


If you only want to print that on errors, there's some risk of running into bugs in recent interpreters. However, you can try the following (first given in this previous answer):

error() {
  local parent_lineno="$1"
  local message="$2"
  local code="${3:-1}"
  if [[ -n "$message" ]] ; then
    echo "Error on or near line ${parent_lineno}: ${message}; exiting with status ${code}"
  else
    echo "Error on or near line ${parent_lineno}; exiting with status ${code}"
  fi
  exit "${code}"
}
trap 'error ${LINENO}' ERR

Again, this will not work on some recent builds of bash, which don't always have LINENO set correctly inside traps.


Another approach (which will only work on recent shells; the below uses some bash 4.0 and 4.1 features) is to use PS4 to emit the exit status and line number of each command to a dedicated file descriptor, and use tail to print only the last line given to that FD before the shell exits:

exec {BASH_XTRACEFD}> >(tail -n 1) # send set -x output to tail -n 1
PS4=':At line $LINENO; prior command exit status $?+'
set -x
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • It is risky if this shell script fails because of bash versions because it will be reused in different shells. I think I will go with the first option of PS4=':$LINENO+'. I don't really want the actual lines because it clutters the console, but if that's the safe way that works everywhere, so be it. – user2441441 Mar 16 '15 at 16:37
  • You can always check `$BASH_VERSION` and use different code depending on the result. – Charles Duffy Mar 16 '15 at 16:49
  • @user2441441, ...alternately, it's easy to make the last code work with older versions of bash *if you don't need stderr for anything else*. – Charles Duffy Mar 16 '15 at 18:41