The Unix Shell: Argh
Suppose you're trying to write a simple shell script. And suppose you very badly want to put a command into a shell variable before you execute it. And suppose that command very badly needs to accept double-quoted strings as arguments. Oh, the layers of indirection! How will the shell tokenize such a thing?
Let the command in question be the following homely shell script.
string-arg.sh:
#! /bin/sh
# Usage: string-arg.sh [-s STRING]*
while test ${1+set}; do
case $1 in
"-s")
if ! test ${2+set}; then
echo "no string after -s"
exit 1
else
echo "string arg=\"$2\""
shift 2
continue
fi
esac
echo "bad arg: $1"
exit 1
done
Let's see what happens.
% ./string-arg.sh -s "quoted arg"
string arg="quoted arg"
% cmd="./string-arg.sh -s \"quoted arg\""
% echo $cmd
./string-arg.sh -s "quoted arg"
% $cmd
string arg=""quoted"
bad arg: arg"
% eval $cmd
string arg="quoted arg"
AND REMEMBER, KIDS:
echo `foo`
gives you the output of foo
and { foo; echo $? }
gives you its exit value. if fooexecutes
then bar
fi
bar
if foo
succeeds (conventionally), which is equivalent to foo && barin the short-circuiting parlance.
if ! fooexecutes
then bar
fi
bar
if foo
fails (conventionally), which is equivalent to foo || barin the short-circuiting parlance.
if `foo`executes
then bar
fi
bar
if the command output by foo
exists and returns exit value 0 (if it doesn't exist, it will just exit). if test `foo`executes
then bar
fi
bar
if foo
doesn't produce any output.[UPDATE] One more thing. Setting shell variables.
% CMD=cmd arg
bash: arg: command not found
% CMD= cmd arg
bash: cmd: command not found
% CMD= "cmd arg"
bash: cmd arg: command not found
% CMD="cmd arg"
% echo $CMD
cmd arg
This often trips me up, because
make
is much more forgiving and I hack more Makefiles than shell scripts.[UPDATE 1/8/2007] I got the if-then stuff wrong the first time. Which goes to show you how desperately I need this tutorial. In shell-world exit code 0 is "true" and exit code not-0 is "false". This is sort of the opposite of the C convention, with the caveat that exit values and arithmetic values shouldn't be conflated.
Another trip-up from C to the shell is that whitespace makes a bigger difference.
if ! foo; then bar; fi
is not the same as if !foo; then bar; fi
. if foois not the same as
then bar
fi
if foo then bar fi
. {foo; bar;}
is not the same as { foo; bar;}
. And so on, world without end.
No comments:
Post a Comment