Scripts with arguments
Just as a UNIX command can take arguments, so can a script.
After all, a script is a command written by a user. The first
argument of a script is referred to within the script as
$1 , the second by $2 , and so on. These
are known as positional parameters. They can be
manipulated like any other variables, except that they cannot be
reset using = . Create a file (argfile ,
say) containing one line:
echo $1 $2
Now run that script, but give it two arguments:
$ sh argfile hello 99
hello 99
There are some other 'variable names' that have special meanings
when used within a script. The name of the script (i.e. the name of
the file containing the script) is denoted by $0 , and
the number of positional parameters by $# . Note that
in this context # does not introduce a comment.
Suppose the following script, called showargs , is
invoked:
This script is $0, and it has $# arguments
First argument is $1
The output we would get would be:
$ sh ./showargs foo bar
This script is ./showargs, and it has 2 arguments
First argument is foo
$ sh showargs "foo bar"
This script is showargs, and it has 1 arguments
First argument is foo bar
Note that $0 uses the name of the script that has
been called. In the second invocation, the first argument of
showargs is the string "foo bar" , not
foo - the quotes around it cause it to be considered
as a single word.
When a script is given many arguments, accessing them one-by-one
using positional parameters is often awkward. We can use
$* to refer to them all at once. In other words, the
value of $* is the single string
"$ 1 $2 $3 ...". In order to experiment
with these parameters, create a script containing
for i in $*
do
echo $i
done
and call it testfile . When it is run, the
$* will be replaced by the arguments of the script;
thus calling testfile with arguments jo ,
sam and george , so
$ testfile jo sam george
would be equivalent to running a script containing:
for i in jo sam george
do
echo $i
done
We must be careful, though; the shell will strip out quotes
before passing arguments to a command, and we need to be able to
handle
$ sh testfile jo "Sue Smith"
sam
in a sensible manner. To this end we can use $@ ,
which is similar to $* . Edit testfile to
replace $* by $@ . In both cases the
result is the same, namely
$ sh testfile jo "Sue Smith"
sam
jo
Sue
Smith
sam
indicating that the quotes have been stripped before the
arguments have been passed to testfile . If, instead,
the first line of the script is
for i in "$*"
the quotes are stripped from the arguments, which are then
enclosed by a new pair of quotes. Thus the string jo Sue
Smith sam is the expansion of $* , which is then
quoted within the script indicating a single string, and the output
is:
$ sh testfile jo "Sue Smith"
sam
jo Sue Smith sam
If, however, "$@" is used, the arguments to the
script are passed without modification, including quotes, to
replace "$@" , and the quotes are then interpreted
within the script:
$ sh testfile jo "Sue Smith"
sam
jo
Sue Smith
sam
If a script requires an indeterminate number of arguments, you
may wish to discard the earlier ones - for instance, if they are
options and you have finished processing all the options. The
command shift will remove $1 from the positional
parameters, $2 will become $1 (etc.), and
$* , $@ and $# will all be
changed accordingly.
Worked example
Write a script called mypager to take arguments
that are files and page each of them in turn using
more . Additionally, mypager may take a
single argument, -i , which will cause a message to be
displayed on the screen before each file is paged, giving the name
of the file, and requiring the user to press Return to
continue.
Solution:
IFLAG=no
if [ "$#" -gt 0 ] # Make sure there are some files
then if [ "$1" = "-i" ] # Check if the option is called
then IFLAG=yes # If so, reset the flag ...
shift # and delete the argument
fi
fi
for i in "$@" # Go through each file in turn
do
if [ "$IFLAG" = "yes" ] # If "-i" ...
then echo "Paging $i" # output message ...
echo "Press Return to continue"
read j # wait for Return
fi
more "$i" # Page the file
done
|