I have a test script which has a lot of commands and will generate lots of output, I use set -x
or set -v
and set -e
, so the script would stop when error occurs. However, it's still rather difficult for me to locate which line did the execution stop in order to locate the problem.
Is there a method which can output the line number of the script before each line is executed?
Or output the line number before the command exhibition generated by set -x
?
Or any method which can deal with my script line location problem would be a great help.
Thanks.
6 Answers
You mention that you're already using -x
. The variable PS4
denotes the value is the prompt printed before the command line is echoed when the -x
option is set and defaults to :
followed by space.
You can change PS4
to emit the LINENO
(The line number in the script or shell function currently executing).
For example, if your script reads:
$ cat script
foo=10
echo ${foo}
echo $((2 + 2))
Executing it thus would print line numbers:
$ PS4='Line ${LINENO}: ' bash -x script
Line 1: foo=10
Line 2: echo 10
10
Line 3: echo 4
4
http://wiki.bash-hackers.org/scripting/debuggingtips gives the ultimate PS4
that would output everything you will possibly need for tracing:
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'

- 33,874
- 19
- 107
- 152

- 118,548
- 33
- 236
- 227
-
12I wonder why no one mentions this for "How to debug shell scripts?" . This is far better than just `echo` – Suvarna Pattayil Jan 15 '14 at 13:00
-
@VusP Agreed, unnecessary `echo` statements are best avoided. – devnull Jan 15 '14 at 13:02
-
You can even output nanosecond times, although at the cost of a considerable slow-down: `PS4='Line $LINENO @ $(date +%s.%N): ' bash -x script` – Walter Tross Nov 17 '14 at 11:07
-
4I can't help but feel that `-x` *should* print line numbers. Or, maybe -`nx` *should* include line numbers. For me, its one of those "WTF" moments... – jww Aug 24 '16 at 01:20
-
1Man, I wish I knew about that PS4 concoction sooner... It would have saved me so many headaches – niken Jul 28 '17 at 17:25
-
9`\033[0;33m+(${BASH_SOURCE}:${LINENO}):\033[0m ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'` for some colors – Ulysse BN Jul 24 '18 at 08:19
-
1How do you use it with functions? – Munavir Chavody Jun 18 '19 at 08:08
-
`export PS4='+(${BASH_SOURCE:-$0}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'` for when `BASH_SOURCE` doesn't tell you the name of the running script. – nikhilweee Mar 05 '22 at 18:27
-
Thank you SO MUCH for providing such an important debugging tool. Why this isn't the standard for "set -x" is beyond me. If I could give you a hundred "Useful" clicks, I would. It appears that the ++ signs indicate nesting level within the bash script. – Tihamer Aug 11 '23 at 14:58
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.
For example:
#!/bin/bash
function log() {
echo "LINENO: ${LINENO}"
echo "BASH_LINENO: ${BASH_LINENO[*]}"
}
function foo() {
log "$@"
}
foo "$@"
See here for details of Bash variables.

- 14,098
- 15
- 84
- 131
PS4 with value $LINENO is what you need,
E.g. Following script (myScript.sh):
#!/bin/bash -xv
PS4='${LINENO}: '
echo "Hello"
echo "World"
Output would be:
./myScript.sh
+echo Hello
3 : Hello
+echo World
4 : World

- 111
- 1
- 3
Workaround for shells without LINENO
In a fairly sophisticated script I wouldn't like to see all line numbers; rather I would like to be in control of the output.
Define a function
echo_line_no () {
grep -n "$1" $0 | sed "s/echo_line_no//"
# grep the line(s) containing input $1 with line numbers
# replace the function name with nothing
} # echo_line_no
Use it with quotes like
echo_line_no "this is a simple comment with a line number"
Output is
16 "this is a simple comment with a line number"
if the number of this line in the source file is 16.
This basically answers the question How to show line number when executing bash script for users of ash or other shells without LINENO
.
Anything more to add?
Sure. Why do you need this? How do you work with this? What can you do with this? Is this simple approach really sufficient or useful? Why do you want to tinker with this at all?
Want to know more? Read reflections on debugging

- 763
- 8
- 13
Simple (but powerful) solution: Place echo
around the code you think that causes the problem and move the echo
line by line until the messages does not appear anymore on screen - because the script has stop because of an error before.
Even more powerful solution: Install bashdb
the bash debugger and debug the script line by line

- 152,036
- 28
- 249
- 266
-
2`echo`ing stuff around can help in many cases, but falls short when you try to apply it in functions that has meaningful, parseable output. – Eliran Malka Apr 25 '17 at 10:10
-
1@EliranMalka Fair point. You may echo to stderr in that case: `echo "foo" >&2` – hek2mgl Apr 25 '17 at 10:13
-
1...one should echo to stderr in _all_ cases when the purpose is messages that are diagnostic in nature. – Charles Duffy Sep 24 '20 at 01:40
If you're using $LINENO
within a function, it will cache the first occurrence. Instead use ${BASH_LINENO[0]}

- 6,504
- 2
- 17
- 13