Tuesday, February 1, 2011

Shell argument handling: $* vs. $@

I never can recall the difference between $* and $@ in scripts so here's a little experiment which should help, hope that I remember this time :-)

First of all there is this little script to show all args of a script, call it args.sh

#!/bin/sh
cnt=0
for arg
do
  cnt=`expr $cnt + 1`
  printf "arg$cnt =\t$arg\n"
done

args.sh 1 "2 3" "4 \"5\" 6"
will show
arg1 = 1
arg2 = 2 3
arg3 = 4 "5" 6
i.e. the script counts and shows three arguments.

In order to test how $* and $@ are passed to sub processes there is a little script test.sh in four variations, once pure and once surrounded by quotes:
#!/bin/sh
args.sh $*
#!/bin/sh
args.sh "$*"
#!/bin/sh
args.sh $@
#!/bin/sh
args.sh "$@"
test.sh 1 "2 3" "4 \"5\" 6"
will lead to
arg1 = 1
arg2 = 2
arg3 = 3
arg4 = 4
arg5 = "5"
arg6 = 6
arg1 = 1 2 3 4 "5" 6
arg1 = 1
arg2 = 2
arg3 = 3
arg4 = 4
arg5 = "5"
arg6 = 6

arg1 = 1
arg2 = 2 3
arg3 = 4 "5" 6
i.e. only the last invocation does what we want: it keeps and forwards the original arguments.

All other invocations either split the arguments by space or concatenate all arguments into one big single argument.

Another little trap I fell into: when trying to save the arguments in a variable neither invocation is successful

#!/bin/sh
a=$*
b="$*"
c=$@
d="$@"

args.sh $a
args.sh $b
args.sh $c
args.sh $d
#!/bin/sh
a=$*
b="$*"
c=$@
d="$@"

args.sh "$a"
args.sh "$b"
args.sh "$c"
args.sh "$d"
all lead to the complete split all lead to a single argument
arg1 = 1
arg2 = 2
arg3 = 3
arg4 = 4
arg5 = "5"
arg6 = 6

arg1 = 1 2 3 4 "5" 6

This is all in Bourne shell (if in doubt).

No comments:

Post a Comment