6

I don't think I fully understand the nuances of quoting in bash.

I have a script, foo.sh, which simply outputs numbered arguments.

#!/bin/bash

i=1
while [ $i -le $# ] ; do
    v=$(eval "echo \$$i")
    echo "$i: $v"
    i=$((i + 1))
done

You can use it like so:

me@localhost] ./foo.sh a b c
1: a
2: b
3: c

If I set the variable args to a value containing a space (like "super nintendo"), I can use no-quoting to have bash treat it as two arguments:

me@localhost] args="super nintendo" ; ./foo.sh $args
1: super
2: nintendo

Or I can use weak-quoting (double quotes) to have bash treat it as a single argument, but expanding the variable to the actual value:

me@localhost] args="super nintendo" ; ./foo.sh "$args"
1: super nintendo

Or I can use strong-quoting (single quotes) to treat it literally as typed:

me@localhost] args="super nintendo" ; ./foo.sh '$args'
1: $args

However, weak quoting the special variable $@ seems to act as if there were no quoting. For example, bar.sh below calls foo.sh twice, once with weak quoting and once with no quoting.

#!/bin/bash

./foo.sh "$@"
./foo.sh $@

Calling this with ./bar.sh a b c produces identical output for both calls to foo.sh:

1: a
2: b
3: c
1: a
2: b
3: c

What I expected to see was the following:

1: a b c
1: a
2: b
3: c

What am I missing with quoting in bash here?

2
  • 1
    Note that you can avoid the eval by using ${!i}.
    – deltab
    Jan 30, 2017 at 2:06
  • 1
    Another way to write the script: i=1; for x; do echo "$((i++)): $x"; done
    – deltab
    Jan 30, 2017 at 2:10

1 Answer 1

13

That's because $@ is an array, and quoting of arrays has different rules:

  • "${array[@]}" or "$@" expands to members of the array
  • "${array[*]}" or "$*" expands to elements of the array joined by the first character from the $IFS variable.

Try it with several arguments, some of them containing spaces:

./foo.sh 'one two' three
2

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .