## 35.20. Handling Command-Line Arguments in Shell Scripts

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.

### 35.20.1. With the "$@" Parameter

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

> NOTE: 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.

### 35.20.2. With a Loop

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.

### 35.20.3. Counting Arguments with $#

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

Copyright © 2003 O'Reilly & Associates. All rights reserved.