Passing arguments to a program is one of the common operations across any language you use. Similarly, in this article, we are going to see how to parse arguments in bash scripts using getopts bash built-in function in Linux.
Table of Contents
Introduction
Every command that we run in the terminal has an argument associated with it. For example, you can take the most basic command in Linux named df which displays file system disk space usage. It accepts arguments/flags like -h
, -i
, --version
, etc.
Similar to this, when you are creating shell scripts depending upon the use case, you may have to process the script based on the argument passed.
There are two ways to parse arguments passed to the script in bash.
One is writing the logic to parse the arguments manually using the special variables $@, $1, $2 … $N. Another way would be to use getopts.
Getopts is a POSIX compatible bash built-in function that accepts short arguments like -h
, -v
, -b
, etc. You cannot pass long arguments like --help
, --version
. If you want to parse long options there is another utility called getopt which is an external program and not bash built-in.
There are three possible scenarios I can think of when working with flags/arguments.
- The script which runs even when no argument or flags are passed.
- The script that accepts flags but with no arguments.
- The script that accepts flags and associated arguments for the flag.
You will learn how to create a bash script satisfying the above scenarios in the upcoming sections.
Getting Help
You can run the following help command to access the getopts help section.
$ getopts -help
Core Construct Of Getopts
There are four important terms you should know about in order to work with getopts.
getopts: getopts optstring name [arg …]
OPTSTRING
- The list of characters that are recognized as arguments. Example:-h
,-v
.OPTNAME
- The parsed argument from$@
will be stored in theOPTNAME
variable. You can use any name as optname.OPTARG
- If there are additional arguments passed then that is stored in theOPTARG
variable.OPTIND
- Index pointing to the next argument to be processed.
When you pass the arguments to the script, they will be stored in variable $@. Getopts will get the list of arguments from $@ use OPTIND
and parse it.
You should specify the list of recognized arguments in OPTSTRING
. While loop is used to iterate over the list of passed arguments and using OPTIND
, getopts will get the argument and store it in OPTNAME
.
The case statement is used to check if the pattern matches with OPTNAME
and run its corresponding statement.
I am going to run the below code throughout the article. This is a simple code to understand. First I have created a function named "help" where there is a usage syntax for my script.
I am using three arguments in OPTSTRING ; "-s
, -T
, -h
". Variable named ARG
is the OPTNAME
used in the below code. The parsed argument will be stored in $ARG
and using the case statement it will try to find if the pattern matches with the argument in the ARG
variable.
Following script will accept flags like -s
, -h
, -T
and you can also combine flags like -shT
.
#!/bin/bash function help(){ echo "USAGE: args.sh -s, -T <arg>, -h" } while getopts ":sT:h" ARG; do case "$ARG" in s) echo "Running -s flag" ;; T) echo "Running -T flag" echo "Argument passed is $OPTARG" ;; h) help ;; :) echo "argument missing" ;; \?) echo "Something is wrong" ;; esac done shift "$((OPTIND-1))"
The functionality of the above code will be explained in detail in the upcoming section.
No Argument Passed
The default behavior of getopts is if no argument is passed, it will not throw an error message and will exit with return code zero.
In some cases, the script should not run when no argument is passed. In that case, you can use conditional statements to check the length of arguments passed ($@
) is zero or not. If no arguments are passed, the script will fail.
Take a look at the below code. I am storing the passed arguments to variable PASSED_ARGS
and checking the length of it. If the length of PASSED_ARGS
is not zero, then while loop
with getopts will run, else help
function will run and the script will exit with return code 1.
PASSED_AGS=$@ if [[ ${#PASSED_ARGS} -ne 0 ]] then while getopts ":sT:h" ARG; do case "$ARG" in s) echo "Running -s flag" ;; T) echo "Running -T flag" echo "Argument passed is $OPTARG" ;; h) help ;; :) echo "argument missing for $ARG" ;; \?) echo "Something is wrong" ;; esac done else help exit 1 fi shift "$((OPTIND-1))"
You can also use the following one-liner to evaluate the arguments passed.
[[ ${#PASSED_ARGS} -ne 0 ]] && echo "Arguments stored in \$@ = $@" || { echo "No argument passed"; help; exit 1; }
Arguments With Flags And Its Supported Arguments
You can either just pass flags like -h
or -s
to the script or flags and associated argument like -T
to it. You should add a colon (:) after the flag identifier (-T
) to make the flag accept the argument.
In the below code, you can see I have added colon (:
) after the identifier T
. It means when I pass the -T
flag to the script, I should pass an additional argument with it.
while getopts ":sT:h" ARG; do
When an argument is passed to the flag it will be stored in the variable $OPTARG
. You have to write logic to capture the variable and process it accordingly. Copy and run the same code from the previous section.
T) echo "Running -T flag" echo "Argument passed is $OPTARG" ;;
You can also combine and run multiple arguments at a time.
Handling Errors
There may be situations where arguments are passed wrongly and the script should throw some errors.
By default, getopts will throw an error message when a flag passed is not in OPTSTRING
or if you fail to pass additional arguments to the flag. Adding a colon to the start of OPTSTRING
will suppress the default error messages.
Let’s remove the colon and run the script again. I am passing -x
as the first argument which is not present in OPTSTRING
. Secondly, -T
requires an additional argument which I failed to provide In both cases it throws me the error.
Now, you can suppress the default error messages and print your own error messages. Take a look at the below patterns from the case statement.
- Colon (:) -> If no additional argument is passed
OPTARG
will be set to colon and you can write logic to print error messages. - \? -> When an argument that is not in
OPTSTRING
is passed,OPTNAME
will be set to "?
".
:) echo "argument missing" ;; \?) echo "Something is wrong" ;;
Use of Shift and OPTIND
If you take any existing scripts written using getopts you will see this statement after while
loop.
shift "$((OPTIND-1))"
When the script is triggered, OPTIND
is set to 1. The OPTIND
points to the position of the next argument to be processed by getopts.
The above statement will remove all the options parsed by the getopts and $1
will not be set to the first non-optional argument passed to the script.
Conclusion
In this article, we have seen how to parse arguments in bash scripts using getopts function. Getopts only supports a short form of arguments and you cannot pass long arguments.
At first, it might seem tricky to work with getopts. But if you understand the core concept, then it gets easy.
Similar Read:
Bash scripting guides:
- How To Create GUI Dialog Boxes In Bash Scripts With Zenity In Linux And Unix
- Bash Scripting – Case Statement
- Bash Scripting – Conditional Statements
- Bash Scripting – String Manipulation
- Bash Scripting – Printf Command Explained With Examples
- Bash Scripting – Indexed Array Explained With Examples
- Bash Scripting – Associative Array Explained With Examples
- Bash Scripting – For Loop Explained With Examples
- Bash Scripting – While And Until Loop Explained With Examples
- Bash Redirection Explained With Examples
- Bash Scripting – Variables Explained With Examples
- Bash Scripting – Functions Explained With Examples
- Bash Echo Command Explained With Examples In Linux
- Bash Heredoc Tutorial For Beginners