Beginners guide to use script arguments in bash with examples

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.

Beginners guide to parse script arguments in bash scripts

 

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

Beginners guide to parse script arguments in bash scripts

 

Let us understand this script:

  • Line 3 to Line 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 from Line 16
  • Line 17 will check for -r or --rpm in the provided first argument and if found store the second input argument with $2 into RPM_NAME variable at Line 18
  • Line 19 will print the content of $RPM_NAME variable
  • Line 20 is used to shift 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 arguments
  • Line 21 will check for -s or --sleep in the first input argument and if found the second input argument will be stored in SLEEP variable using $2 argument in Line 22
  • Line 23 will print the SLEEP value collected at Line 22
  • Line 24 is again important as we will perform a shift operation
  • Line 25 to 28 will be executed if no matching input arguments found by printing the usage function
  • Line 29 again contains shift to make sure the script doesn't end up in an infinite loop
  • Line 30 will end the while 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:
Beginners guide to parse script arguments in bash scripts

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.

Leave a Comment

Please use shortcodes <pre class=comments>your code</pre> for syntax highlighting when adding code.