BASH Debugging – Quick Tips
Almost everyone knows (or should know) the basic options in bash debug.
-v Print shell input lines as they are read.
-x Print commands and their arguments as they are executed.
Sounds easy right?
See the difference, a practical example, a simple and silly script to demonstrate this:
billy@sles:~/lab> cat bashdebug.sh #!/bin/bash TODAY=`date +%F` for number in 01 02 03; do echo "Hey, the number is: $number";done echo "And today is $TODAY" billy@sles:~/lab>
If we run it, we get:
billy@sles:~/lab> bash bashdebug.sh Hey, the number is: 01 Hey, the number is: 02 Hey, the number is: 03 And today is 2013-04-19 billy@sles:~/lab>
Now let’s see how BASH it reads:
billy@sles:~/lab> bash -v bashdebug.sh #!/bin/bash TODAY=`date +%F` date +%F for number in 01 02 03; do echo "Hey, the number is: $number";done Hey, the number is: 01 Hey, the number is: 02 Hey, the number is: 03 echo "And today is $TODAY" And today is 2013-04-19 billy@sles:~/lab>
And how it runs or “expand”
billy@sles:~/lab> bash -x bashdebug.sh ++ date +%F + TODAY='2013-04-19' + for number in 01 02 03 + echo 'Hey, the number is: 01' Hey, the number is: 01 + for number in 01 02 03 + echo 'Hey, the number is: 02' Hey, the number is: 02 + for number in 01 02 03 + echo 'Hey, the number is: 03' Hey, the number is: 03 + echo 'And today is 2013-04-19' And today is 2013-04-19 billy@sles:~/lab>
Notice that when we use this option the output has a prefix “+”
These options may seem trivial, but believe me: in big scripts it saves big headaches.
In addition to this we can use:
-u Exit the script after empty vars.
For example, let’s change the script a little bit:
billy@sles:~/lab> cat bashdebug.sh #!/bin/bash TODAY=`date +%F` echo "Today is $TODAY" for number in 01 02 03; do echo "Hey, the number is: $number";done billy@sles:~/lab>
Run:
billy@sles:~/lab> bash bashdebug.sh Today is 2013-04-19 Hey, the number is: 01 Hey, the number is: 02 Hey, the number is: 03 billy@sles:~/lab>
Works fine, but what happens if we don’t set the var $TODAY?
billy@sles:~/lab> cat bashdebug.sh #!/bin/bash #TODAY=`date +%F` echo "Today is $TODAY" for number in 01 02 03; do echo "Hey, the number is: $number";done billy@sles:~/lab>
billy@sles:~/lab> bash bashdebug.sh Today is Hey, the number is: 01 Hey, the number is: 02 Hey, the number is: 03 billy@sles:~/lab>
Still works, not fine, but works, then how can we debug this? Of course, with -u
billy@sles:~/lab> bash -u bashdebug.sh bashdebug.sh: line 3: TODAY: unbound variable billy@sles:~/lab>
And we get the error! And again, one headache less.
And the next option:
-e Exit the script after simple errors.
And yes, example:
Bash does not stop at simple errors, with this option we force it to do so.
billy@sles:~/lab> cat bashdebug.sh #!/bin/bash source ./dontexist.conf TODAY=`date +%F` echo "Today is $TODAY" for number in 01 02 03; do echo "Hey, the number is: $number";done billy@sles:~/lab>
Run:
billy@sles:~/lab> bash bashdebug.sh bashdebug.sh: line 2: ./dontexist.conf: No such file or directory Today is 2013-04-19 Hey, the number is: 01 Hey, the number is: 02 Hey, the number is: 03 billy@sles:~/lab>
Of course it doesn’t exist, but the script is still running. Debug this? yes, with -e
billy@sles:~/lab> bash -e bashdebug.sh bashdebug.sh: line 2: ./dontexist.conf: No such file or directory billy@sles:~/lab>
This forces us to pay more attention to details.
Finally, we can use all these options together (-vxue), to invoke the script.
We can even use it selectively within the script using: set -/+, example:
billy@sles:~/lab> cat bashdebug.sh #!/bin/bash source ./dontexist.conf set -u TODAY=`date +%F` echo "Today is $TODAY" set +u for number in 01 02 03; do echo "Hey, the number is: $number";done billy@sles:~/lab>
Of course there are many more options and many more ways to debug bash, as the article title suggests, this is just a brief guide.
Happy Hacking!
Related Articles
Mar 17th, 2023