How to Debug Shell Scripts
In order to find out where the problem is with my script, I often use echo for
debugging, print line number with echo ${LINENO}
, but it is not a optimium way
for shell script debugging.
Shell debug/verbose mode
The best way to do shell script debugging is to utilize the debugging mode(-v -x),
simply append -x
, -v
or -xv
at the end of shebang line for whole script
debugging, like this:
#!/bin/bash -x
# count words in string
foo="foo bar and 2000"
echo ${LINENO}
words=($foo)
echo ${#words[@]}
echo ${LINENO}
set -- $foo
echo $#
echo ${LINENO}
wc -w <<< "$foo"
The output of the above script will be like this:
If using verbose mode, the output will be:
Another way to do this is to execute shell script preceding with bash -x
bash -x test.sh
bash -v test.sh
bash -xv test.sh
Debugging parts of the script
If we are sure only part of the script have issue, then use set -x
at the start
of the code need to be debugging, and unset xtrace mode with set +x
at the end
of the code.
#!/bin/bash
# count words in string
foo="foo bar and 2000"
echo ${LINENO}
words=($foo)
echo ${#words[@]}
set -x
echo ${LINENO}
set -- $foo
echo $#
set +x
echo ${LINENO}
wc -w <<< "$foo"
Show line number in debug mode
Shell debug mode is useful for trouble shooting, it would be more useful if adding source file, function and line number to the output. Do this with:
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
This is the example output after add source file, function and line number:
+(test.sh:5): main(): foo='foo bar and 2000'
+(test.sh:7): main(): echo 7
7
+(test.sh:8): main(): words=($foo)
+(test.sh:9): main(): echo 4
4
+(test.sh:11): main(): echo 11
11
+(test.sh:12): main(): set -- foo bar and 2000
+(test.sh:13): main(): echo 4
4
+(test.sh:15): main(): echo 15
15
+(test.sh:16): main(): wc -w
4