Last updated on March 1, 2021 by Dan Nanni
A bash script rarely runs standalone. Rather, you often pass one or more arguments to the script from the command line to modify its run-time behavior. The script then reads the supplied arguments, parse and process them accordingly. In more advanced cases, you may want to pass command-line options to your script (e.g., "-h" or "-f my.txt") to optinally change the default settings of the script. In this tutorial let's find out how you can pass command-line arguments and how you can handle command-line options in a bash shell script.
The command-line arguments that are passed to a bash script are called positional parameters because how these arguments are referenced inside a script depends on the position of the arguments in the command line. More specifically, the command-line arguments are referenced by digits that are incrementing in the order of appearance in the command line (e.g., $1 for the first argument, $2 for the second argument, ..., $N for the N-th argument). When you access the N-th argument where N contains more than one digits (e.g., the 10-th argument), you need to surround N with {} (e.g., ${10}). $0 is a special bash parameter that stores the name of a bash script.
The following bash script example checks if the first (second) argument exists, and prints its value if it does.
if [ -z $1 ]; then echo "The first argument is not set" else echo "The first argument: $1" fi if [ ! -z $2 ]; then echo "The second argument: $2" else echo "The second argument is not set" fi
If you want to check the total number of arguments passed to a bash script, you can use a special bash parameter called $#.
if [ $# -ne 3 ]; then echo "You need to provide three arguments" exit 1 fi
if [ $# -lt 1 ] || [ $# -gt 2 ]; then echo "Number of arguments must be between 1 and 2" exit 1 fi
for
LoopAnother way to check command-line arguments in a bash script is by referencing a special bash parameter called $@, which expands to a list of supplied command-line arguments. Since $@ is an iterable list, you can use for
loop to read each argument in the list. For example:
pos=1 for arg in "$@"; do echo "$pos-th argument : $arg" (( pos += 1 )) done
Note that you need to surround $@ with quotes in case any command-line argument contains whitespaces. When you run this script, you will see the following output.
$ ./script.sh 100 linux "hi there"
1-th argument : 100 2-th argument : linux 3-th argument : hi there
getopts
The previous two methods access ordinary command-line arguments. In some cases, however, you may want to handle command-line options in a shell script, which may or may not be specified from the command line. The command-line options are typically single letters preceded by a single hyphen. Some options are used standalone (e.g., -h), while other options and their arguments are provided together (e.g., -f file.txt). When a shell script reads command-line options, what matters is not the position of an option in the command line, but rather what option flag is used.
Bash provides a built-in function called getopts
to handle such command-line options. It's much easier to learn getopts
with examples.
while getopts 'hi:f:' OPTION; do case "$OPTION" in h) echo "Option h is given" ;; i) iarg="$OPTARG" echo "Argument provided with option i: $iarg" ;; f) farg="$OPTARG" echo "Argument provided with option f: $farg" ;; *) echo "Usage: $0 [-h] [-i value] [-f filename]" >&2 exit 1 ;; esac done
In the example script above, the while
loop iterates each of all possible command-line options and processes them. The string that follows getopts
indicates possible option flags accepted by this script. Our example accepts "-h", "-i" and "-f" flags. The ":" sign after an option flag (e.g., "-i" and "-f") indicates that the option requires an argument. For those options that take an argument, an actual argument value is passed as $OPTARG. The case statement with "*" is a catch-all statement which is matched when any unsupported command-line option is entered.
Note that the entire while
loop can be skipped if no command-line option is supplied from the command line.
In the final scenario, let's say a given script takes (optional) command-line options as well as (required) positional parameters. The following example script handles such a scenario, which combines the example scripts from Method One and Method Three.
while getopts 'hi:f:' OPTION; do case "$OPTION" in h) echo "Option h is given" ;; i) iarg="$OPTARG" echo "Argument provided with option i: $iarg" ;; f) farg="$OPTARG" echo "Argument provided with option f: $farg" ;; *) echo "Usage: $0 [-h] [-i value] [-f filename]" >&2 exit 1 ;; esac done shift "$(($OPTIND -1))" if [ -z $1 ]; then echo "The first argument is not set" else echo "The first argument: $1" fi if [ ! -z $2 ]; then echo "The second argument: $2" else echo "The second argument is not set" fi
One important statement in the above example is the following line.
shift "$(($OPTIND - 1))"
$OPTIND is a special bash variable which is set to 1 upon launch of this script. As each option field is parsed, $OPTIND is incremented by one. shift
is a built-in function which moves positional parameters. When shift N
is called, it discards the first-N positional parameters from the command line. Thus the above statement discards all command-line options (if any) that are processed, leaving only subsequent ordinary command-line arguments, so that we can reference them using $1, $2, etc.
For example, when you run the script with the following arguments:
$ ./script -f my.txt argument1 argument2
You will see this output as expected:
Argument provided with option f: my.txt The first argument: argument1 The second argument: argument2
bash
shell scripting tutorials provided by Xmodulo.This website is made possible by minimal ads and your gracious donation via PayPal or credit card
Please note that this article is published by Xmodulo.com under a Creative Commons Attribution-ShareAlike 3.0 Unported License. If you would like to use the whole or any part of this article, you need to cite this web page at Xmodulo.com as the original source.
Xmodulo © 2021 ‒ About ‒ Write for Us ‒ Feed ‒ Powered by DigitalOcean