How to pass and store arguments to shell script? How to parse input arguments inside shell script? How to pass arguments to a function inside shell script in bash? How to read command line arguments in shell script?
In this tutorial we will cover these questions covering bash script arguments with multiple scenarios and examples. I will try to be as detailed as possible so even a beginner to Linux can easily understand the concept.
How input arguments are parsed in bash shell script
Generally we pass arguments to a script using this syntax
~]# ./eg_1.sh first second third fourth
Now to store all these arguments inside the script in a single variable we can use "$@
"
But to store these arguments in individual variable, you can assign the values based on the numerical position of the input argument. You can check this sample script where I am storing upto 4 arguments in individual variables. You can use any names for the variable, I have used these just for better understanding. Here any argument after 4th place will be ignored.
Let,s execute this script:
~]# ./eg_1.sh first second third fourth
Input argument list:
First argument: first
Second argument: second
Third argument: third
Fourth argument: fourth
So as expected the script has successfully stored the input arguments and printed them on the screen
Method 1: Parse input arguments with if condition and while loop
In this example we will use if condition to parse the input arguments and perform respective action. Here I have written a small script which is expected to collect following input arguments
-h
or--help
should print the usage function-r [RPM]
or--rpm [RPM]
will just print the provided rpm name on the console-s [VAL]
or--sleep [VAL]
will just [print the sleep value on the console
#!/bin/bash
function show_usage() {
printf "Usage: $0 [optiona [parameters]]\n"
printf "\n"
printf "Options:\n"
printf " -r|--rpm [rpm_name], print rpm name\n"
printf " -s|--sleep, Provide the value to sleep\n"
printf " -h|--help, Print help\n"
return 0
}
while [ ! -z "$1" ]; do
if [[ "$1" == "--help" ]] || [[ "$1" == "-h" ]]; then
show_usage
elif [[ "$1" == "-r" ]] || [[ "$1" == "--rpm" ]]; then
RPM_NAME="$2"
echo "rpm name is $RPM_NAME"
shift
elif [[ $1 == "-s" ]] || [[ "$1" == "--sleep" ]]; then
SLEEP="$2"
echo "sleep value is $SLEEP"
shift
else
echo "Incorrect input provided $1"
show_usage
fi
shift
done
Script snippet with Line Numbers:
Let us understand this script:
Line 3
toLine 12
are my usage function which should be clear enough.Line 14
I am using a while loop if[ ! -z "$1" ]
condition which will make sure that our if condition will continue to be checked until there are no further input arguments. This is a more robust solution rather than assigning individual arguments to a variable as here we don't have to worry about the order of input arguments.Line 15
will check for--help
or-h
for the first input argument and if found it will print the usage function content fromLine 16
Line 17
will check for-r
or--rpm
in the provided first argument and if found store the second input argument with$2
intoRPM_NAME
variable atLine 18
Line 19
will print the content of$RPM_NAME
variableLine 20
is used toshift
the position so that we don't have to use$3
next time as that may be confusing and alot of things can go wrong so shift is very important when dealing with input argumentsLine 21
will check for-s
or--sleep
in the first input argument and if found the second input argument will be stored inSLEEP
variable using$2
argument inLine 22
Line 23
will print theSLEEP
value collected atLine 22
Line 24
is again important as we will perform ashift
operationLine 25
to28
will be executed if no matching input arguments found by printing theusage
functionLine 29
again containsshift
to make sure the script doesn't end up in an infinite loopLine 30
will end thewhile
loop
You can execute the script by shuffling the order of input arguments and it should still work. Although I am not a big fan of this method as it is very messy and I would prefer case over if condition if the number of input arguments is more than 3.
~]# ./eg_1.sh -r kernel -s 10 rpm name is kernel sleep value is 10 ~]# ./eg_1.sh -s 10 -r kernel sleep value is 10 rpm name is kernel
When should we use "shift" when working with input arguments
- You may get confused as in when should you use
shift
when working with input arguments. - If your input arguments don't expect a value for the respective argument then you can ignore shift, as you can see I didn't used
shift
for-h
or--help
in the above script - If you are using a loop to parse through your argument then you have to use shift depending upon your requirement. If your input arguments don't expect a value then a shift is required near the end of the loop only.
- Consider a scenario wherein you have to collect ~10 input arguments and some of them may expect input value for respective arguments so it would be very hard to manage with
$1, $2 ..
to collect the input arguments - So we use
while
loop with shift operation so that the loop will iterate over the available input arguments - With
while
loop we will always deal with$1
and$2
for the input arg and arg's value so the solution is cleaner - Once you have the value you can perform shift so we again start from
$1
- If you have a requirement to only collect 2-3 input arguments you can avoid shift if it feels too complicated for you.
Method 2: Parse input arguments with case statement and while loop
In this example we will use case statement with while
loop to check for input arguments. As you can see the script looks much cleaner compared to the one with if
condition:
while [ ! -z "$1" ];do case "$1" in -h|--help) show_usage ;; -r|--rpm) shift RPM_NAME="$1" echo "rpm name is $RPM_NAME" ;; -s|--sleep) shift SLEEP="$1" echo "sleep value is $SLEEP" ;; *) echo "Incorrect input provided" show_usage esac shift done
I don't think I need to again explain this part of the script line by line. Here I have switched the position of shift so now if $1
matches the condition such as -r
or --rpm
then I do the shift
so now second argument has become the first for me so I store the first argument into RPM_NAME
and print the same
We can execute the script and verify in any possible order:
~]# ./eg_1.sh -s 10 -r kernel sleep value is 10 rpm name is kernel ~]# ./eg_1.sh -r kernel -s 10 rpm name is kernel sleep value is 10
Handling exceptions and errors with bash script arguments
Scenario 1: Missing value for input argument
In all the examples above we also worked on success use case. But what if you were expecting an input argument with a value but the user forgot to pass a value? In such case your entire loop can break. Let's use the above case statement to demonstrate this:
~]# ./eg_1.sh -r -s 10 rpm name is -s Incorrect input provided Usage: ./eg_1.sh [options [parameters]] Options: -r|--rpm [rpm_name], Print rpm name -s|--sleep, Provide the value to sleep -h|--help, Print help
As expected I did not gave a value for -r
so -s
was considered as the rpm name and then 10 was considered as an input argument. Since we have not defined 10
as a supported input arg, the script failed and printed the usage
function.
So it is very important that we handle such error scenarios. Now the handling may vary from case to case. For example if you are only expecting an integer as a value for some input argument then you can add that check, let me show you some examples:
#!/bin/bash
function show_usage() {
printf "Usage: $0 [optiona [parameters]]\n"
printf "\n"
printf "Options:\n"
printf " -r|--rpm [rpm_name], print rpm name\n"
printf " -s|--sleep, Provide the value to sleep\n"
printf " -h|--help, Print help\n"
return 0
}
while [ ! -z "$1" ];do
case "$1" in
-h|--help)
show_usage
;;
-r|--rpm)
shift
RPM_NAME="$1"
[[ $RPM_NAME =~ ^- ]] && echo "$RPM_NAME is not a proper value for -r|--rpm" && show_usage
echo "rpm name is $RPM_NAME"
;;
-s|--sleep)
shift
SLEEP="$1"
[[ $SLEEP =~ ^- ]] && echo "$SLEEP is not a proper value for -s|--sleep" && show_usage
echo "sleep value is $SLEEP"
;;
*)
echo "Incorrect input provided"
show_usage
esac
shift
done
In this script I have added below addition check:
[[ $RPM_NAME =~ ^- ]] && echo "$RPM_NAME is not a proper value for -r|--rpm" && show_usage [[ $SLEEP =~ ^- ]] && echo "$SLEEP is not a proper value for -s|--sleep" && show_usage
So we know that all our input arguments start with hyphen so if the value of input argument starts with hyphen then it means that a value was not provided.
Let's test this script, and it works perfectly this time:
~]# ./eg_1.sh -r -s 10 -s is not a proper value for -r|--rpm Usage: ./eg_1.sh [options [parameters]] Options: -r|--rpm [rpm_name], Print rpm name -s|--sleep, Provide the value to sleep -h|--help, Print help
Scenario 2: Count input arguments list
Another possible scenario of failure would be where we expect only 2 input arguments but the user gives more then 2 input arguments, so we should add a check for supported arguments:
Here we will count the list of minimum supported arguments and if it is greater than 3 then print a message with usage section and exit:
if [ $# -gt 3 ];then echo "Only 3 input arguments supported" show_usage exit 1 fi while [ ! -z "$1" ];do case "$1" in -h|--help) show_usage ;; <output trimmed>
Let's verify our script:
# ./eg_1.sh -r -s 10 -a Only 3 input arguments supported Usage: ./eg_1.sh [options [parameters]] Options: -r|--rpm [rpm_name], Print rpm name -s|--sleep, Provide the value to sleep -h|--help, Print help
Scenario 3: When script is executed without any argument
Similarly what if the user executes the script without any input argument? In such case also we should exit by showing the usage section:
if [[ $# -gt 3 ]] || [[ $# -eq 0 ]];then echo "Either 0 or more than 3 input arguments provided which is not supported" show_usage exit 1 fi while [ ! -z "$1" ];do case "$1" in -h|--help) show_usage ;; <output trimmed>
So I have added one more check in the same if condition, let's verify this script:
~]# ./eg_1.sh Either 0 or more than 3 input arguments provided which is not supported Usage: ./eg_1.sh [options [parameters]] Options: -r|--rpm [rpm_name], Print rpm name -s|--sleep, Provide the value to sleep -h|--help, Print help
Similarly you can add multiple checks based on your requirement.
Conclusion
In this tutorial I showed you different examples to executed input arguments with bash scripts. You can use similar logic when handling input arguments for functions in shell scripts. If you have any custom scenario which you need help with then you can use the comment box below to give as much detail as possible and I will try to help you out.
Lastly I hope the steps from the article to learn bash script arguments on Linux was helpful. So, let me know your suggestions and feedback using the comment section.