How To Validate the Syntax of a Linux Bash Script Before Running It

Configurare noua (How To)

Situatie

Bugs and typos in Linux Bash scripts can do dire things when the script is run. Here are some ways to check the syntax of your scripts before you even run them.

  • Those Pesky Bugs

Writing code is hard. Or to be more accurate, writing bug-free non-trivial code is hard. And the more lines of code there are in a program or script, the more likely it becomes that there will be bugs in it. The language you program in has a direct bearing on this. Programming in assembly is much tougher than programming in C, and programming in C is more challenging than programming in Python. The more low-level the language you’re programming in, the more work you have to do yourself. Python might enjoy in-built garbage-collection routines, but C and assembly certainly don’t.

Writing Linux shell scripts poses its own challenges. With a compiled language like C, a program called a compiler reads your source code—the human-readable instructions you type into a text file—and transforms it into a binary executable file. The binary file contains the machine code instructions that the computer can understand and act upon.

The compiler will only generate a binary file if the source code it’s reading and parsing obeys the syntax and other rules of the language. If you spell a reserved word—one of the command words of the language—or a variable name incorrectly, the compiler will throw an error.

For example, some languages insist you declare a variable before you use it, others are not so fussy. If the language you’re working in requires you to declare variables but you forget to do that, the compiler will throw a different error message. As annoying as these compilation-time errors are, they do catch a lot of problems and force you to address them. But even when you’ve got a program that has no syntactical bugs it doesn’t mean there are no bugs in it. Far from it.

Bugs that are due to logical flaws are usually much harder to spot. If you tell your program to add two and three but you really wanted it to add two and two, you won’t get the answer you expected. But the program is doing what it has been written to do. There’s nothing wrong with the composition or syntax of the program. The problem is you. You’ve written a well-formed program that doesn’t do what you wanted.

  • Testing Is Difficult

Thoroughly testing a program, even a simple one, is time-consuming. Running it a few times isn’t enough; you really need to test all execution paths in your code, so that all parts of the code are verified. If the program asks for input, you need to provide a sufficient range of input values to test all conditions—including unacceptable input.

For higher-level languages, unit tests and automated testing help to make thorough testing a manageable exercise. So the question is, are there any tools that we can use to help us write bug-free Bash shell scripts?The answer is yes, including the Bash shell itself.

  • Using Bash To Check Script Syntax

The Bash -n (noexec) option tells Bash to read a script and check it for syntactical errors, without running the script. Depending on what your script is intended to do, this can be a lot safer than running it and looking for problems.

Here’s the script we’re going to check. It isn’t complicated, it’s mainly a set of if statements. It prompts for, and accepts, a number representing a month. The script decides which season the month belongs to. Obviously, this won’t work if the user provides no input at all, or if they provide invalid input like a letter instead of a digit.

#! /bin/bash

read -p "Enter a month (1 to 12): " month

# did they enter anything?
if [ -z "$month" ]
then
  echo "You must enter a number representing a month."
  exit 1
fi

# is it a valid month?
if (( "$month" < 1 || "$month" > 12)); then
  echo "The month must be a number between 1 and 12."
  exit 0
fi

# is it a Spring month?
if (( "$month" >= 3 && "$month" < 6)); then
  echo "That's a Spring month."
  exit 0
fi

# is it a Summer month?
if (( "$month" >= 6 && "$month" < 9)); then
  echo "That's a Summer month."
  exit 0
fi

# is it an Autumn month?
if (( "$month" >= 9 && "$month" < 12)); then
  echo "That's an Autumn month."
  exit 0
fi

# it must be a Winter month
echo "That's a Winter month."
exit 0

This section checks whether the user has entered anything at all. It tests whether the $month variable is unset.

if [ -z "$month" ]
then
  echo "You must enter a number representing a month."
  exit 1
fi

This section checks whether they have entered a number between 1 and 12. It also traps invalid input that isn’t a digit, because letters and punctuation symbols don’t translate into numerical values.

# is it a valid month?
if (( "$month" < 1 || "$month" > 12)); then
  echo "The month must be a number between 1 and 12."
  exit 0
fi

All of the other If clauses check whether the value in the $month variable is between two values. If it is, the month belongs to that season. For example, if the month entered by the user is 6, 7, or 8, it is a Summer month.

# is it a Summer month?
if (( "$month" >= 6 && "$month" < 9)); then
  echo "That's a Summer month."
  exit 0
fi

If you want to work through our examples, copy and paste the text of the script into an editor and save it as “seasons.sh.” Then make the script executable by using the chmod command:

chmod +x seasons.sh

Setting the executable permission on a script

We can test the script by

  • Providing no input at all.
  • Providing a non-numeric input.
  • Providing a numerical value that is outside the range of 1 to 12.
  • Providing numerical values within the range of 1 to 12.

In all cases, we start the script with the same command. The only difference is the input the user provides when promoted by the script.

./seasons.sh

Testing a script with a variety of valid and invalid inputs

That seems to work as expected. Let’s have Bash check the syntax of our script. We do this by invoking the -n (noexec) option and passing in the name of our script.

bash -n ./seasons.sh

Using Bash to test the syntax of a script

This is a case of “no news is good news.” Silently returning us to the command prompt is Bash’s way of saying everything seems OK. Let’s sabotage our script and introduce an error.

We’ll remove the then from the first if clause.

# is it a valid month?
if (( "$month" < 1 || "$month" > 12)); # "then" has been removed
  echo "The month must be a number between 1 and 12."
  exit 0
fi

Now let’s run the script, first without and then with input from the user.

./seasons.sh

Testing a script with invalid and valid inputs

The first time the script is run the user doesn’t enter a value and so the script terminates. The section that we’ve sabotaged is never reached. The script ends without an error message from Bash.

The second time the script is run, the user provides an input value, and the first if clause is executed to sanity-check the user’s input. That triggers the error message from Bash. Note that Bash checks the syntax of that clause—and every other line of code—because it doesn’t care about the logic of the script. The user isn’t prompted to enter a number when Bash checks the script, because the script isn’t running.

Solutie

Tip solutie

Permanent

Voteaza

(6 din 12 persoane apreciaza acest articol)

Despre Autor

Leave A Comment?