Sams Teach Yourself Shell Programming in 24 Hours
(Publisher: Macmillan Computer Publishing)
Author(s): Sriranga Veeraraghavan
ISBN: 0672314819
Publication Date: 01/01/99

Previous Table of Contents Next


Syntax Checking

When dealing with any shell script, check the syntax of the script before trying to execute it. This enables you to fix most problems.

To enable syntax checking, use the -n option as follows:

/bin/sh -n script arg1 arg2argN

Here script is the name of a script and arg1 through argN are the arguments for that script. This command generates output only if errors occur in the specified script.

Check the syntax of the following script (the line numbers are included for your reference):

     1  #!/bin/sh
     2
     3  YN=y
     4  if [ $YN = "yes" ]
     5      echo "yes"
     6  fi

Can you spot the error?

If this script is stored in the file buggy1.sh, check its syntax as follows:

$ /bin/sh -n ./buggy1.sh

The output looks like the following:

./buggy1.sh: syntax error at line 7: 'fi' unexpected

This tells you that when the shell tried to read line 7, it found that the fi statement on line 6 was unexpected. By now you have probably figured out that the reason the shell was trying read line 7 is that the if statement on line 4

if [ $YN = "y" ]

is not terminated with a then statement. This line should read as follows:

if [ $YN = "y" ] ; then

Making this change, you find that the syntax of the script is okay because the command

$ /bin/sh -n buggy1.sh

produces no output.

Why You Should Use Syntax Checking

After looking at the shell script in the previous example, you might be wondering why you couldn’t simply execute the shell script to determine the problem. After all, the command

$ /bin/sh ./buggy1.sh

produces the output

buggy1.sh: syntax error at line 7: 'fi' unexpected

This output is identical to the output of the following command:

$ /bin/sh -n ./buggy1.sh

For this script, it does not matter whether you use the syntax checking mode, but this is not always the case. As an example, consider the following script (the line numbers are included for your reference):

     1  #!/bin/sh
     2
     3  Failed() {
     4      if [ $1 -ne 0 ] ; then
     5          echo "Failed. Exiting." ; exit 1 ;
     6      fi
     7      echo "Done."
     8  }
     9
    10  echo "Deleting old backups, please wait… \c"
    11  rm -r backup > /dev/null 2>&1
    12  Failed $?
    13
    14  echo "Make backup (y/n)? \c"
    15  read RESPONSE
    16  case $RESPONSE in
    17      [yY]|[Yy][Ee][Ss]|*)
    18          echo "Making backup, please wait… \c"
    19          cp -r docs backup
    20          Failed
    21      [nN]|[Nn][Oo])
    22          echo "Backup Skipped." ;;
    23  esac

There are at least three errors in this script. See if you can find them.

If this script is in a file called buggy2.sh, executing it produces the following output:

Deleting old backups, please wait… Done.
Make backup (y/n)?

Entering y at the prompt produces the following error:

./buggy3.sh: syntax error at line 21: ')' unexpected

Due to a bug in the script, you can’t make a backup, and you have already lost your previous backup. As you can imagine, this is a very bad situation.

The reason the script gets that far before detecting an error is that the shell reads and executes each line of a shell script individually, just like it does on the command line. Here the shell reads and executes lines until it encounters a problem.

By using the -n option, the script does not execute. Instead, each line is checked to make sure that it has the correct syntax. This helps you avoid the situation encountered by running the buggy2.sh script because only the error is reported:

./buggy2.sh: syntax error at line 21: ')' unexpected

Using Verbose Mode

Now that you know why syntax checking should be employed, you can track down the source of the problem.

Looking at line 21 of buggy2.sh

21      [nN]|[Nn][Oo])

it is hard to see why the shell thinks the parenthesis ) is unexpected. Sometimes knowing where a syntax error occurs is not enough—you have to know the context in which the error occurs.

The shell provides you with the -v (v as in verbose) debugging mode in order to check the context in which a syntax error occurs. When this option is specified, the shell prints each line of a script as it is read.

If you issue the -v option by itself, every line in the script will execute. Because you want to check the syntax, you combine the -n and -v options as follows:

$ /bin/sh -nv script arg1 arg2argN

If you execute buggy2.sh with the debugging options

$ /bin/sh -nv ./buggy2.sh

the output looks like the following (the line numbers are provided for your reference):

     1  #!/bin/sh
     2
     3  Failed() {
     4      if [ $1 -ne 0 ] ; then
     5          echo "Failed. Exiting." ; exit 1 ;
     6      fi
     7      echo "Done."
     8  }
     9
    10  echo "Deleting old backups, please wait… \c"
    11  rm -r backup > /dev/null 2>&1
    12  Failed $?
    13
    14  echo "Make backup (y/n)? \c"
    15  read RESPONSE
    16  case $RESPONSE in
    17      [yY]|[Yy][Ee][Ss])
    18          echo "Making backup, please wait… \c"
    19          cp -r docs backup
    20          Failed
    21      [nN]|[Nn][Oo])
⇒./buggy2.sh: syntax error at line 21: ')' unexpected

From this output, the reason that the shell issues an error is apparent. The problem is on line 20; the first pattern of the case statement is not terminated with the ;;. Make the change

Failed ;;

or

Failed
;;

to fix this script. After making this change, the command

$ /bin/sh -n buggy2.sh

does not produce an error message. As you will see in the next section, this does not necessarily mean that the script is free from bugs.

However, this is not to say that you should not use these modes. You should always make sure that these commands do not complain about syntax errors. It is much easier to concentrate on the real bugs, either in logic or program flow, when you know that major syntax errors are not present in your script.

For readers familiar with the C programming language, syntax checking your shell scripts using sh -n or sh -nv is equivalent to checking your source files with lint.


Previous Table of Contents Next