To write flexible shell scripts, you
usually want to give them command-line arguments. As you've seen in other articles (Section 35.16, Section
35.17), $1
holds the first
command-line argument. The Bourne shell can give you arguments through the
ninth, $9
. The Korn shell and some other
newer Bourne-type shells understand ${10}
for
the tenth argument, and so on.
If you've been
reading this series (Section
35.2) of articles in order, you saw the zmore (Section
35.17) script that accepted just one command-line argument.
If you
put "$@"
in a script, the shell will
replace that string with a quoted (Section 27.12) set of the script's
command-line arguments. Then you can pass as many arguments as you want,
including pathnames with unusual characters
(Section 14.11):
% zmore report memo "savearts/What's next?"
The third argument has a perfectly legal filename; we see more and more of them on our system — especially filesystems that are networked to computers like the Macintosh, or on systems that use windowing systems to run graphical programs such as FrameMaker, where spaces and other "special" characters in filenames are common. Double-quoting all arguments through the script helps to be sure that the script can handle these unusual but legal pathnames.
In this case, we want the arguments to be passed to the GNU zcat command. Let's change the zmore script to read:
zcat "$@" >$temp
When the shell runs the script with the arguments shown above, the command line will become:
zcat "report" "memo" "savearts/What's next?" >/tmp/zmore12345
On
some Bourne shells, if there are no command-line arguments, the "$@"
becomes a single empty argument (Section 37.5), as if you'd typed
this:
zcat "" >/tmp/zmore12345
In this case, the zcat command would complain that it can't find a file. (Of course, in this script, the case would prevent this problem. But not all scripts test the number of arguments.)
On those shells, you can replace "$@"
with ${1+"$@"}
(Section 36.7). That means
that if $1
is defined, "$@"
should be used. A not-quite-as-good
fix is to replace "$@
" with $*
. It gives you an unquoted list of
command-line arguments; that's usually fine but can cause trouble on
pathnames with special characters in them.
A for
loop (Section
35.21) can step through all command-line arguments, one by one.
You can also use a while loop (Section 35.15) that tests $#
(see below) and removes the arguments one
by one with the shift command (Section 35.22). The getopt and getopts (Section 35.24) commands handle
arguments in a more standard way.
The $#
parameter counts the number of command-line arguments. For
instance, if there are three arguments, $#
will contain 3
. This is
usually used for error-checking (as in the zmore script in Section
35.17) with case (Section 35.10) or test (Section
35.26).
— JP