1. Introduction
We’ve previously examined how to pass command-line arguments to a bash script. In this tutorial, we’ll take a look at how we can use these arguments inside the bash script.
2. Processing the Input
Let’s take a look at the different ways to process the arguments passed to a bash script inside the script.
2.1. Positional Parameters
Arguments passed to a script are processed in the same order in which they’re sent. The indexing of the arguments starts at one, and the first argument can be accessed inside the script using $1. Similarly, the second argument can be accessed using $2, and so on. The positional parameter refers to this representation of the arguments using their position.
Let’s take an example of the following script, userReg-positional-parameter.sh, which prints username, age, and full name in that order:
echo "Username: $1";
echo "Age: $2";
echo "Full Name: $3";
Now let’s run this script with the three input parameters:
sh userReg-positional-parameter.sh john 25 'John Smith'
The output will be:
Username : john
Age: 25
Full Name: John Smith
2.2. Flags
Using flags is a common way of passing input to a script. When passing input to the script, there’s a flag (usually a single letter) starting with a hyphen (-) before each argument.
Let’s take a look at the userReg-flags.sh script, which takes three arguments: username (-u), age (-a), and full name (-f).
We’ll modify the earlier script to use flags instead of relying on positional parameters. The getopts function reads the flags in the input, and OPTARG refers to the corresponding values:
while getopts u:a:f: flag
do
case "${flag}" in
u) username=${OPTARG};;
a) age=${OPTARG};;
f) fullname=${OPTARG};;
esac
done
echo "Username: $username";
echo "Age: $age";
echo "Full Name: $fullname";
Let’s run this script with the same input as before, only this time, we’ll add flags to the input:
sh userReg-flags.sh -f 'John Smith' -a 25 -u john
The output is the same as before, though we have shifted the positions of the username and full name arguments:
Username : john
Age: 25
Full Name: John Smith
Here we’re using the getopts function to parse the flags provided as input, and the case block to assign the value specified to the corresponding variable.
2.3. Loop Construct
Positional parameters, while convenient in many cases, can’t be used when the input size is unknown. The use of a loop construct comes in handy in these situations.
The variable $@ is the array of all the input parameters. Using this variable within a for loop, we can iterate over the input and process all the arguments passed.
Let’s take an example of the script users-loop.sh, which prints all the usernames that have been passed as input:
i=1;
for user in "$@"
do
echo "Username - $i: $user";
i=$((i + 1));
done
Now let’s run the script:
sh users-loop.sh john matt bill 'joe wicks' carol
And we’ll see our output:
Username - 1: john
Username - 2: matt
Username - 3: bill
Username - 4: joe wicks
Username - 5: carol
In the above example, we’re iterating the user variable over the entire array of input parameters. This iteration starts at the first input argument, john, and runs until the last argument, carol, even though the size of the input is unknown.
2.4. Shift Operator
Shift operator in bash (syntactically shift n, where n is the number of positions to move) shifts the position of the command line arguments. The default value for n is one if not specified.
The shift operator causes the indexing of the input to start from the shifted position. In other words, when this operator is used on an array input, the positional parameter $1 changes to the argument reached by shifting n positions to the right from the current argument bound to positional parameter $1.
Consider an example script that determines whether the input is odd or even:
sh parityCheck.sh 13 18 27 35 44 52 61 79 93
From the above discussion on the positional parameter, we now know that $1 refers to the first argument, which is 13. Using the shift operator with input 1 (shift 1) causes the indexing to start from the second argument. That is, $1 now refers to the second argument (18). Similarly, calling shift 2 will then cause the indexing to start from the fourth argument (35).
Let’s again take a look at the example of users script discussed above. Instead of using the $@ variable and iterating over it, we’ll now use the shift operator. The $# variable returns the input size:
i=1;
j=$#;
while [ $i -le $j ]
do
echo "Username - $i: $1";
i=$((i + 1));
shift 1;
done
Let’s run the script with the same input as above:
sh users-shift-operator.sh john matt bill 'joe wicks' carol
The output will be the same as before:
Username - 1: john
Username - 2: matt
Username - 3: bill
Username - 4: joe wicks
Username - 5: carol
In this example, we’re shifting the positional parameter in each iteration by one until we reach the end of the input. Therefore, $1 refers to the next element in the input each time.
3. Conclusion
In this article, we looked at how arguments passed to a bash script during runtime can be processed inside the script in different ways:
- Positional parameters can be used when the input size is fixed and the order of the arguments in the input is known.
- With flags, the order of the arguments in the input doesn’t matter.
- Loop construct comes in handy when the input size is unknown.
- Shift operator causes indexing to start from the argument at the shifted position.
- The variable $@ returns the array of input parameters, and $# returns the size of the input array.
As always, the examples used in this article are available on GitHub.