A shell script is written to achieve a purpose, and it is very helpful is the shell script takes multiple commandline arguments and then operate on each argument, instead of execute the shellscript multiple times. This post will talk about how to make the shell script work with multiple arguments.

Command line Arguments

The command line arguments passed are stored in a special variables. These are $1, $2, $3, $4, …. , $9. After $9 parameters needs to be bounded in brackets like ${10}, ${11}, ${12}, … etc. These are called the positional parameters. On the other hand $* and $@ Which stores all the passed arguments. $# is another special variable which holds the number of command line arguments passed.

Now if some one passes a lot of arguments to your shell script then they will be stored in the correnponding variables. Don’t worry we will not make a long manual reading to get the variables.

We will use the shift to fetch the command line arguments one by one in a single variable, and keep the implementation compact. First we know some information about the shift command.

Shifting the Arguments

shift is a bash builtin feature. This shifts the passed argument variables to the left. The syntax of shift is shift N where N is a non-negative integer. The man page says

The positional parameters from n+1 … are renamed to $1 …. Parameters represented by the numbers $# down to $#-n+1 are unset. n must be a non-negative number less than or equal to $#. If n is 0, no parameters are changed. If n is not given, it is assumed to be 1. If n is greater than $#, the positional parameters are not changed. The return status is greater than zero if n is greater than $# or less than zero; otherwise 0.

The thing what happens in simple language is: shift 1 will make the following shifts

$1 <- $2
$2 <- $3
$3 <- $4
$4 <- $5
$5 <- $6
$6 <- $7
..
..
$N-1 <- $N

And the value of $1 is discarded

And shift 5 will do the following

$1 <- $6
$2 <- $7
$3 <- $8
$4 <- $9
$5 <- ${10}
$6 <- ${11}
..
..
$N-5 <- $N

The value of $1, $2, $3, $4, $5 are discarded

Also after each shift the value of $# (the number of arguments) is also adjusted. Note that the variable $0 does not take part in the shift operation.

The default shift amount is 1, when nothing is passed to shift.
One thing to note is that, if you give some shift amount which is greater than $# or some negative value, then shift is not performed, and shift will return non-zero. If shift is performed then only shift will return zero. So if there is 3 commandline arguments present and we shift 5 then the shift will not be performed and shift will return nonzero. Remember this as we would soon need this.

Shift and Read

If we read from $1 and then shift once, then again read from $1 we will get the value of $2 before shifting, and shifting again will get the value of the actual $3 inside $1. Thus while the value $# is not zero we can iterate on a while loop get the value of $1 shift and again access $1 and get all the parameters.

#!/bin/bash

while [ $# -ne 0 ]
  do
    echo "Current Parameter: $1 , Remaining $#"
    #Pass $1 to some bash function or do whatever
    shift
done

Or even we could check if the current value of $1 is NULL or not to check for the termination of the loop.

#!/bin/bash

while [ -n "$1" ]
  do
    echo "Current Parameter: $1 , Remaining $#"
    #Pass $1 to some bash function or do whatever
    shift
done

More

Okay, now to talk about a special case. Although we need to shift 1 place at a time, but if you need to shift the parameters more than one say x , but there are nx+k parameters, that is $# is not divisible by x , then after performing n shifts there would remain k more arguments which is less than x and shift will not be performed, and the while loop will never terminate.
For example modify any of the above code by changing shift 5 and pass some arguments to the script such that the number of arguments are not divisible by 5, for example pass 7 arguments say a b c d e f g. You will notice that after the first shift $1 is now f and 2 more arguments are in the list. After the first shift no more shifts will be performed, and neither $1 will be NULL nor $# will become zero, and the while loop will iterate infinitely.
To solve this we will use the exit status of shift . Adding a check that if $? is non-zero or not immediately after shift will let us know if shift was performed, if it is non-zero, then we break from the loop.

#!/bin/bash

while [ -n "$1" ]
  do
    echo "Current Parameter: $1 , Remaining $#"
    #Pass $1 to some bash function or do whatever
    shift 5
    if [ $? -ne 0 ]
      then
        break
    fi
done

Note that the $? should be check immediately after shift before it overwrites the exit status of shift with some other program’s exit status.

Links

To get more, read the below documentations.

http://tldp.org/LDP/abs/html/othertypesv.html
http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_09_07.html

Advertisement

8 thoughts on “Read multiple arguments in bash script

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s