A common requirement when writing a shell script is the need to pass arguments to it via the command-line. This allows us to control the behavior of the script without relying on another file or environment variables.
To handle options on the command line, we can use a facility in the shell called positional parameters. These are a series of special variables ($0 through $9) that contain the contents of the command line.
sh script.sh verbose production deploy $0 = script.sh $1 = verbose $2 = production $3 = deploy
For simple scripts, this approach may work fine. But this approach requires us to specify the options in the correct order and it is not immediately obvious what each parameter is used for.
A more robust and flexible approach is to use enhanced getopt which is based on a C library that is capable of parsing arguments in a variety of different ways. It doesn't care about the order and can handle spacing and quoting.
Not that getopt and getopts are two different utilities and should not be confused with one another.
Getopt is ubiquitious across Linux distributions. To check if you have the enhanced version, do this:
getopt --test echo $? 4
The exit code should be 4.
Getopt gives us a number of ways to accept options:
- Short options
- Long options
- Non-option parameters
A short option is composed of a hyphen (-) followed by a single letter and can also include an argument.
- No arguments
sh script.sh -v -a
sh script.sh -f outfile.txt
A long option is composed of a two hyphens (--) followed by a word. It can also include an argument.
- No argument
sh script.sh --verbose
sh script.sh --file=outfile.txt
The Option String
In order for getopt to know what we want, we need to build an option string.
Normally, we pass 2 option strings to getopt, one for short options and the other for long options.
We can mix and match short and long options when we run our script.
Option string for short options
- Each single character stands for an option.
- A single colon (:) means that the option has a required argument or value.
- A double colon (::) means that the option has an optional argument or value.
Say we want our script to accept the following short options:
-v Enable verbose mode -f <file>Specify output filename
Our option string would be:
There are no colons following "v" because it does not accept an arguments For "f", there is a single colon following it because it requires an argument. Note that the order of the letters here does not matter.
Option string for long options
- Options are separated by , (comma character).
- A : (colon character) tells that the option has a required argument.
- A :: (two consequent colon character) tells that the option has an optional argument.
Following the example above, our option string for long options would be:
Putting it all together, let's create a script that handles the following options:
#!/bin/bash # Parse command-line options # Option strings SHORT=vf: LONG=verbose,file: # read the options OPTS=$(getopt --options $SHORT --long $LONG --name "$0" -- "$@") if [ $? != 0 ] ; then echo "Failed to parse options...exiting." >&2 ; exit 1 ; fi eval set -- "$OPTS" # set initial values VERBOSE=false # extract options and their arguments into variables. while true ; do case "$1" in -v | --verbose ) VERBOSE=true shift ;; -f | --file ) FILE="$2" shift 2 ;; -- ) shift break ;; *) echo "Internal error!" exit 1 ;; esac done # Print the variables echo "VERBOSE = $VERBOSE" echo "FILE = $FILE"
sh script.sh --verbose --file test.txt VERBOSE = true FILE = test.txt sh script.sh -v -f test.txt VERBOSE = true FILE = test.txt sh script.sh -f test.txt VERBOSE = false FILE = test.txt