Other arguments used with positional parameters

We have up to 9 positional parameters on the command line and in fact we can use more than 9 arguments but we will look at that in some detail shortly.

$# How many positional arguments have we got ?

Using a special variable called $#.

One of the ways we can use this (we'll see when we come to decisions and if-then statements) is to check how many arguments were used to run a script. Let's imagine that we want our script eatout.sh to be executed with at least one argument.

We would include something like:

if $# < 1
echo "Usage: ...."
exit 1
                

in our script.

Why would we exit with a value of 1? Because we didn't execute the script correctly.

We can use a number of positional arguments to print out useful information about how to use our script.

$* - display all positional parameters

We've got yet another useful construct, $*, which tells us all the positional arguments.

Let's look at an example of this:

#!/bin/bash
DATE=$(date +"%d %b %Y %H:%M")
TYPE=$1
echo "The arguments asked for: $*"
echo "Queried on $DATE"
grep $TYPE restaurants.txt |sort +3n
exit 0
                

If we then ran our script eatout.sh with:

./eatout.sh italian 5
                

We would get the following output:

riaan@debian:~> ~/ham$ ./eatout.sh italian 5
The arguments asked for: italian 5
Queried on 01 Dec 2003 21:36
italian,Bardellis,6973434,5
                

So even if we had 20 positional arguments, it would show us each one of them storing them all in $*.

Using the "shift" command - for more than 9 positional parameters

I said we only have 9 positional parameters, but that's not true, you can have many more than 9. How do we get hold of them?

If we thought of the positional arguments as a list: we've got positional argument 0 which is the name of the shell script or the name of the program, but we never modify that one.

Then we have positional arguments 1 to 9 and we may have additional positional arguments.

To obtain the arguments, we can use the shift command, which will shift arguments to the left. Thus argument 2 would become 1 after a shift, 3 would become 2, 4 would become 3, etc. At the end of the list, 9 would become 8, 10 would become 9, etc.

Figure 6.1. Using Shift Command to access parameters

Using Shift Command to access parameters

If we said:

shift 5
                

it would shift the first 5 positional arguments off the front, and bring 5 additional arguments from the end.

If you were crazy enough to have more than 9 positional arguments for a script, you could shift repeatedly until you get all the positional arguments. Thus you can shift positional arguments off the command line, which allows you to get hold of additional arguments above the 9 positional parameter limit.

It's a good idea to save your positional arguments so that you can use them at a later stage. You never know when you're going to actually need to use an original argument sent into the script. In the eatout.sh script, I saved the type of restaurant ($1) storing it in the variable TYPE.

Exercises:

  1. Create a script that can take up to 15 arguments. Shift the first 9 from the list and print the remaining arguments using the $* construct.

  2. Write a script to read a person's name, surname and telephone number on the command line and write this to a file for later use, using a comma to separate the firstname, surname and telephone number.

  3. Write a script to swap the name and surname as given on the command line and return to the console.

Exit status of the previous command

A final dollar command for now, is $?. $? tells you the exit status of the previous command. So if you ran your eatout.sh script, and as soon as it's finished, you echo $? - assuming that it all ran correctly - you would expect that it would return a 0. Why is that? Because you exited your script with an exit status value of 0.

Let's assume you tried to do something in your script that doesn't work, then you could say:

if $?<>0
echo "Some previous command failed"
                

This test checks whether the previous command ran correctly and, if not (i.e. The output of the previous command was non-zero) a message to that effect is printed to the screen. So 0 is the exit status of the previous command.

If you run a command like:

ping -c1 199.199.199.1
                

Wait for it to complete. And then run:

echo $?
                

you should get a non-zero value. Why? Because the command (ping) never exited properly, and thus a non-zero value is returned. Compare that to the output of:

ping -c1 127.0.0.1
echo $?
                

which should always return a value:

0
                

Why? Because it can ping your local loop-back address. So every command exits with an exit value and you can test the exit value that it exits with, using $?.

Even if you did an:

echo "Hello"
echo $?
                

It would return a value 0, because it was able to print the string 'Hello' to the screen.