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