Fun with shell $ arguments

Two of the best reasons for building shell scripts on Unix systems are 1) to repeat complex sets of instructions without having to rediscover or even retype the commands, and 2) to repeat complex sets of instructions against any number of targets -- thus the need to supply arguments to your scripts.

Arguments provided to shell scripts, such as when you type "doit this that" are available for testing, manipulation and action within your scripts. The arguments themselves are available as $1, $2, $3 and so on -- or you can reference all of them at once using $@. The $0 argument displays the name of your script itself while $# represents the number of arguments provided to the script. The following script segment, for example, will add a message to a log file if the script is run without the correct number of arguments:

#!/bin/bash

if [ $# != 3 ]; then
    echo "$0: wrong number of arguments provided" >> $0.log
fi

It's always a good idea to verify that arguments have been provided before you allow your script to work with them, though you can decide whether to abort if too many arguments are provided or just ignore the extras. So, we could change the code above to look like this:

#!/bin/bash

if [ $# -lt 3 ]; then
    echo "$0: wrong number of arguments provided" >> $0.log
fi

You can also write a script so that it prompts the user to provide arguments if none are provided.

#!/bin/bash

if [ $# == 0 ]; then
    echo -n "Enter position number> "
    read posno
else
    posno=$1
fi

If you're interested in doing something special with the final argument provided to a script, you can grab it using a command like this:

eval lastarg=\${$#}

The interpretation of this command is "the value of argument N where N equals the number of arguments".

To loop through the arguments provided to a script, you can use a "for args in $@" command or you can omit the "in $@" and just use "for args" (or "for x" or "for i" or "for next" or whatever variable name appeals to you). Whenever the "in ..." part of the for command is omitted, the loop runs as if "in $@" was provided.

for args
do
    ...
done

Another possible option to capture the last argument is to use $_. This variable represents the argument provided to the previous command. For example, if you type "ls /usr/local/bin" on the command line and then "cd $_", you will end up in /usr/local/bin since that value will have been assigned to $_.

To use $_ in a script, you have to be careful to make sure that it's picking up the right thing. In this snippit, $_ ends up with the value of the last argument provided only because of the echo $@ command on the line before.

#!/bin/bash

echo $@
last=$_
echo $last

The $_ variable can be very handy on the command line, though, and maybe trouble (though less reassuring) as modifying commands saved in your command history. This example might clarify how it works:

$ echo one two three
one two three
$ echo $_
three
$ echo "one two three"
one two three
$ echo $_
one two three

Notice how enclosing the string in quotes turns it into a single argument.

While we're looking at $ variables, we shouldn't overlook $$ (current process ID) or $! (process ID of last process run in the background). These can be very handy when used in scripts.

Here's a list of the variables covered in this post:

$1, $2, $3, ...		arguments 1-3 and so on
$@			all arguments
$0			script name
$#			number of arguments
\${$#}			the last (rightmost) argument
$?			the return code from a script
$_			last argument to the previous command
$$			current process ID
$!			process ID of last process run in the background
From CIO: 8 Free Online Courses to Grow Your Tech Skills
Join the discussion
Be the first to comment on this article. Our Commenting Policies