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:
Q:
$cat script... for arg in $* do echo "Argument is $arg" done $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:
A:
$1 $2
A: [not <">$1<"> <">$2<">-JP ] if there are two arguments.
Hence the for loop reads:
A:
for arg in 1 2 3 4
A: Note that the quotes are gone. What you wanted the shell to see was:
A:
for arg in '1 2 3' 4
A: You cannot get that, but you can get something that is Good Enough:
A:
"$@" | for arg in "$@" |
|---|
A: In effect, $@ expands to:
A:
$1" "$2
A: Putting ""s around $@, the effect is:
A:
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:
A:
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 ]:
A:
for arg do echo "Argument is $arg" done
A: produces:
A:
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:
A:
$1" "$2...$n-1" "$n
A: (where n is the number of arguments), when there are no arguments:
A:
"$@"
A: expands to:
A:
""
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:
A:
%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.
- in comp.unix.questions on Usenet, 18 March 1988