home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  

UNIX Power Tools

UNIX Power ToolsSearch this book
Previous: 46.6 Watch Out for Bourne Shell -e Bug Chapter 46
Shell Script Debugging and Gotchas
Next: 46.8 Test Built-In Commands for Failure

46.7 Quoting and Command-Line Parameters

Q: I need to pass a shell script some arguments with multiple words. I thought that putting quotes (8.14 ) around command-line arguments would group them. The shell script seems to ignore the quoting, somehow. Here's a simple example:


$ cat script

for arg in $*
    echo "Argument is $arg"
$ script '1 2 3' 4

Argument is 1
Argument is 2
Argument is 3
Argument is 4

A: This is the way $* is defined to work. $* expands to:


$1 $2

A: [not <">$1<"> <">$2<"> -JP  ] if there are two arguments. Hence the for loop reads:


for arg in 1 2 3 4

A: Note that the quotes are gone. What you wanted the shell to see was:


for arg in '1 2 3' 4

A: You cannot get that, but you can get something that is Good Enough:


for arg in "$@"

A: In effect, $@ expands to:


$1" "$2

A: Putting "" s around $@ , the effect is:


for arg in "$1" "$2"

A: Shell quoting is unnecessarily complex. The C shell actually has the right idea (variables can be set to "word lists" (47.5 ) ; argv is such a list), but its defaults and syntax for suppressing them make for an artless programming language:


foreach arg ($argv:q)      # colon q ?!?

A: For the special case of iterating a shell variable over the argument list as it stands at the beginning of the iteration, the Bourne shell provides the construct for arg do [i.e., no in list -JP  ]:


for arg
do echo "Argument is $arg"

A: produces:


Argument is 1 2 3
Argument is 4

A: "$@" is still needed for passing argument lists to other programs. Unfortunately, since $@ is defined as expanding to:


$1" "$2...$n-1

" "$n

A: (where n is the number of arguments), when there are no arguments:



A: expands to:



A: and "" produces a single argument. [Many UNIX vendors considered this a bug and changed it so that it produces no arguments. -JP  ] The best solution for this is to use, for example:


% cat bin/okeeffe

#! /bin/sh
exec rsh okeeffe.berkeley.edu -l torek ${1+"$@"}

A: The construct ${1+"$@"} means "expand $1 , but if $1 is defined, use "$@" instead." [You don't need this on Bourne shells with the "bug fix" I mentioned. -JP  ] Hence, if there are no arguments, we get $1 (which is nothing and produces no arguments), otherwise we get "$@" (which expands as above). ${ var + instead } is one of several sh \*(lqexpansion shortcuts\*(rq (45.12 ) . Another more generally useful one is ${ var-default } , which expands to $ var , but if var is not set, to default instead. All of these can be found in the manual for sh , which is worth reading several times, experimenting as you go.

- CT in comp.unix.questions on Usenet, 18 March 1988

Previous: 46.6 Watch Out for Bourne Shell -e Bug UNIX Power Tools Next: 46.8 Test Built-In Commands for Failure
46.6 Watch Out for Bourne Shell -e Bug Book Index 46.8 Test Built-In Commands for Failure

The UNIX CD Bookshelf NavigationThe UNIX CD BookshelfUNIX Power ToolsUNIX in a NutshellLearning the vi Editorsed & awkLearning the Korn ShellLearning the UNIX Operating System