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.
In Bash, $LINENO contains the line number where the script currently executing. If you need to know the line number where the function was called, try $BASH_LINENO . Note that this variable is an array.
${} Parameter Substitution/Expansion A parameter, in Bash, is an entity that is used to store values. A parameter can be referenced by a number, a name, or by a special symbol.
If you use = in sed the line number will be printed on a separate line and is not available in the pattern space for manipulation. However, you can pipe the output into another instance of sed to merge the line number and the line it applies to. Show activity on this post. = is used to print the line number.
In Bash, $LINENO contains the line number where the script currently executing. If you need to know the line number where the function was called, try $BASH_LINENO. Note that this variable is an array. #!/bin/bash function log () { echo "LINENO: $ {LINENO}" echo "BASH_LINENO: $ {BASH_LINENO [*]}" } function foo () { log "$@" } foo "$@"
You can change PS4 to emit the LINENO (The line number in the script or shell function currently executing). $ PS4='Line $ {LINENO}: ' bash -x script Line 1: foo=10 Line 2: echo 10 10 Line 3: echo 4 4
First use the -n option to print line numbers for a matching string shell: If you need the output on a single line add one more pipe to tr command to remove all new line characters and replace them with single space:
If you use set -e, or trap ... ERR to automatically detect errors, note that they have some caveats. It's also harder to include a description of what the script was doing at the time (as you did in your example), though that might be more useful to a regular user than just the line number.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With