Credit: stevanovicigo / Getty If you run into problems building, testing or running complex bash scripts, don’t lose heart. There are many ways you can help ensure that your scripts will work flawlessly. In this post, we’ll examine some ways you can lessen the likelihood of errors and how to go about doing some simple but very effective troubleshooting. Through a combination of robust logic that tests for possible problems and some troubleshooting to help detect errors, your scripts are likely to be ready for showtime very quickly. Building the outer edges first One way to avoid syntactical errors in scripts is to start your for and while loops, case statements and if/then commands using the outer logic first. If you start your script logic using a syntactical “skeleton”, you won’t forget to end it properly. for i in list while [condition] case "$1" in if [ condition ]; then do do str1) cmd;; cmds cmds cmds *) cmd;; else done done esac cmds fi Go back and fill in the details after you put the basic command framework in place. Verifying script arguments To help ensure that a script won’t run into runtime problems, make sure it checks that the correct number of arguments are being provided and that any files provided as arguments actually exist. Here are some examples of implementing these checks. Check the # of arguments if [ $# -lt 2 ]; then echo "Usage: $0 lines filename" exit else numlines=$1 filename=$2 fi Notice that a usage statement is generated if the arguments don’t match what is expected, and the script is then exited. Check the type of an argument if [[ $numlines != [0-9]* ]]; then echo "Error: $numlines is not numeric" exit fi Check that a file exists if [ ! -f $filename]; then echo "Error: File $filename not found" exit fi Turning on bash debugging Another way to test scripts it to turn on debugging. This will help you verify that they’re working properly or pinpoint any lines in the script that might be causing problems. You can turn on what is often called “debug mode” by using -x as an argument to bash. It helps in debugging by displaying each line in a script as it is being executed. This allows you to see which commands are working as expected and which are not. You can use -x in one of two ways. You can start your script like this: $ bash -x myscript or you can insert the -x into the “shebang line” at the top of the script: #!/bin/bash -x Putting the -x option in the shebang line means you don’t have to type “bash -x scriptname”. Just remember to remove the “-x” once your debugging is complete. You can also elect to turn debugging on for only a portion of a script. To do this, add “set -x” before the section of the script you want debug and “set +x” to turn debugging off after that section. set -x while [ $i -le 2 ] do echo Number: $i ((i++)) done set +x The -v bash option works similarly to -x, but it displays each line in a script as it being read. This means that you will see the entire script and then its output as it is run. You can also use both with -xv as you bash argument (i.e., bash -xv). Here’s an example of using the bash -x form of debugging for a script that is intended to display the top lines of a file: $ bash -x showtop ++ date +%s + STARTTIME=1622138266 ++ - 1622138266 showtop: line 4: -: command not found + echo 'It takes seconds to complete this task...' It takes seconds to complete this task... + '[' 0 -lt 2 ']' + echo 'Usage: showtop lines filename' Usage: showtop lines filename + exit The fourth line of theh below output indicates that there’s a problem. For some reason, the script is looking for a command named “-“. Soon after, we see a usage statement indicating something is wrong with the arguments and the line above suggests that none were provided. In this case, the first error came about because $ENDTIME has no value at that point in the script, making $ENDTIME equal to an empty string, thus the calculation on the second line ends up being just “- 1622138266” and is clearly invalid. #!/bin/bash STARTTIME=$(date +%s) timing=`expr $ENDTIME - $STARTTIME` echo "It takes $timing seconds to complete this task" That timing calculation belongs near the bottom of the script following collecting the ending time value using the date command as is in this corrected version: #!/bin/bash STARTTIME=$(date +%s) if [ $# -lt 2 ]; then echo "Usage: $0 lines filename" exit else numlines=$1 filename=$2 fi if [[ $numlines != [0-9]* ]]; then echo "Error: $numlines is not numeric" exit fi if [ ! -f $filename ]; then echo "Error: File $filename not found" exit else echo top of file head -$numlines $filename fi ENDTIME=$(date +%s) timing=`expr $ENDTIME - $STARTTIME` echo "It took $timing seconds to complete this task" Below is an example of running the repaired script in debug mode. Some of bottom lines (those shown in bold) are the intended script output. The other lines are the debugging output. $ bash -x showtop 10 oldScript ++ date +%s + STARTTIME=1622143586 + '[' 2 -lt 2 ']' + numlines=3 + filename=oldScript + [[ 3 != [0-9]* ]] + '[' '!' -f oldScript ']' + echo top of file top of file + head -3=10 oldScript #!/bin/bash STARTTIME=$(date +%s) echo "It takes $($ENDTIME - $STARTTIME) seconds to complete this task..." if [ $# -lt 2 ]; then echo "Usage: $0 lines filename" exit else numlines=$1 ++ date +%s + ENDTIME=1622143586 ++ expr 1622143586 - 1622143586 + timing=0 + echo 'It took 0 seconds to complete this task...' It took 0 seconds to complete this task... Wrap-Up Having scripts verify arguments and using the -x debugging option to pinpoint flaws can be extremely handy in getting scripts ready for use, especially for those which are far longer and more complicated than the example used in this post. Related content how-to How to find files on Linux There are many options you can use to find files on Linux, including searching by file name (or partial name), age, owner, group, size, type and inode number. By Sandra Henry Stocker Jun 24, 2024 8 mins Linux opinion Linux in your car: Red Hat’s milestone collaboration with exida With contributions from Red Hat and critical collaborators, the safety and security of automotive vehicles has reached a new level of reliability. By Sandra Henry Stocker Jun 17, 2024 5 mins Linux how-to How to print from the Linux command line: double-sided, landscape and more There's a lot more to printing from the Linux command line than the lp command. Check out some of the many available options. By Sandra Henry Stocker Jun 11, 2024 6 mins Linux how-to Converting between uppercase and lowercase on the Linux command line Converting text between uppercase and lowercase can be very tedious, especially when you want to avoid inadvertent misspellings. Fortunately, Linux provides a handful of commands that can make the job very easy. By Sandra Henry Stocker Jun 07, 2024 5 mins Linux PODCASTS VIDEOS RESOURCES EVENTS NEWSLETTERS Newsletter Promo Module Test Description for newsletter promo module. Please enter a valid email address Subscribe