When the bash scripts get big, its often hard to debug while relying only on echo statements trying to trace the error causing statements and functions.
Thankfully there is a setting that can be used to enable debugging and can help you start debugging in a second.
using xtrace -x
At the beginning of a script just add set -x
which enables the xtrace mode and then prints out each command it executes before outputting the result.
enabling and disabling -x
The option can also be enabled for specific parts of the script and then disabled by just using set +x
. So anything between set -x
and set -x
will have the trace enabled.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash
var1='A'
var2='B'
my_function () {
local var1='C'
var2='D'
echo "Inside function: var1: $var1, var2: $var2"
}
echo "Before executing function: var1: $var1, var2: $var2"
set -x
my_function
set +x
echo "After executing function: var1: $var1, var2: $var2"
Output:
Before executing function: var1: A, var2: B
+ my_function
+ local var1=C
+ var2=D
+ echo 'Inside function: var1: C, var2: D'
Inside function: var1: C, var2: D
+ set +x
After executing function: var1: A, var2: D
so the debugging is enabled only around the function which allows us to see what variables are passed like for line 9
it uncovers the variables:
echo "Inside function: var1: $var1, var2: $var2"
to
+ echo 'Inside function: var1: C, var2: D'
Inside function: var1: C, var2: D
enabling -x debug via command line arguments
If you do not want to add the option to script itself then we can pass the -x as commandline argument to enable debugging for the whole script like:
Output debug logs to a file (works with bash 4.1 or higher)
If you do not want to clutter the terminal with the debug logs then we can also output the logs to a file using exec 5> logs.txt
which will output the debug logs to logs.txt rather than printing them on console.
Then to format the log output you can use PS4='[${BASH_SOURCE[0]:-inherited}:${LINENO}:${FUNCNAME[0]:-main}] '
to add filename and line number to every log statement.
Output:
[./debug.sh:19:main] my_function
[./debug.sh:11:my_function] local var1=C
[./debug.sh:12:my_function] var2=D
[./debug.sh:13:my_function] echo 'Inside function: var1: C, var2: D'
[./debug.sh:20:main] set +x