Messing up with command-line arguments in Bash: $*, $@, "$*", "$@",…

It’s stupid, but it took me a good hour to figure this out, so maybe I’m not the only one…

I’ve recently had a problem with command-line arguments in my Java program. The problem was that command line arguments containing spaces were parsed incorrectly, i.e. chopped into individual arguments. My initial suspect was gnu.Getopt package I use for parsing arguments, but as it turned out I was wrong.

The real culprit was a shell wrapper script I used to wrap my java code. The code was the following:

java <some parameters> <programm.class> $@

See the problem? I didn’t. You need quotes around "$@" in which case the parameter gets expanded to: "$1" "$2" "$3"... With no quotes the shell expands it to $1 $2 $3, hence all parameters containing spaces get chopped (also globbing takes place in this case).

BTW: There’s also "$*" which is used to combine all parameters into a single one, i.e, "$*" expands to "$1c$2c$3c..., where c is $IFS (or space). Here it’s also important to have it enclosed in quotes.

6 Responses to “Messing up with command-line arguments in Bash: $*, $@, "$*", "$@",…”

  1. Dan White Says:

    I just spent an hour trying to figure this out. My problem was that I was using $* instead of $@. Watch out for that!

  2. Rogan Creswick Says:

    ah, you just saved me an hour or more :) Thanks for sharing!

  3. David Says:

    Nice one. If found the problem with $@ quickly but not the solution (actually I first thought there might be a problem with the parsing library). Of course, in hindsight, a peek at the man page would have helped:

    man bash

    … @ Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, each parameter expands to a sepa- rate word. That is, “$@” is equivalent to “$1″ “$2″ … When there are no positional parameters, “$@” and $@ expand to nothing (i.e., they are removed). …

  4. Roman Says:

    Excellent. This was very useful. Thanks!

  5. Mac Says:

    I found the problem and the solution after about an hour as well, then discarded the solution because it didn’t look like it was working. I was using ‘echo’ display the expanded java command and parameters, and it seems that echo strips off quotes, so the output looked the same and I assumed it wasn’t going to work.

    In this example, the command is:

    test.sh -p “a b c”

    echo $JAVA_HOME/bin/java com.example.MyClass “$@” —? /usr/java/jdk1.5.0_12/bin/java com.example.MyClass -p a b c

    echo $JAVA_HOME/bin/java com.example.MyClass $@ —> /usr/java/jdk1.5.0_12/bin/java com.example.MyClass -p a b c

    No difference, I thought, so that back to the drawing board.

    BUT, after reading this blog, I tried again and executed with sh -x, I see:

    • echo /usr/java/jdk1.5.0_12/bin/java com.example.MyClass -p ‘a b c’ /usr/java/jdk1.5.0_12/bin/java com.example.MyClass -p a b c
    • echo /usr/java/jdk1.5.0_12/bin/java com.example.MyClass -p a b c /usr/java/jdk1.5.0_12/bin/java com.example.MyClass -p a b c

    doh!

    Thanks!

  6. lowrykun Says:

    Dude – it’s 2009 and this page is still dolling out love!

    Thanks for the tip!

Leave a Reply