3

With the following code:

#! /bin/bash                         
                                     
declare -a arr=("element1"           
                "element2" "element3"
                "element4" )         
echo "1"                             
echo "${arr[@]}"                     
                                     
echo "2"                             
echo ${arr[*]}                       

The output is:

1
element1 element2 element3 element4
2
element1 element2 element3 element4

So the output is the same.

So when is mandatory use one approach over the other?

Manuel Jordan
  • 1,414
  • 9
  • 33
  • 2
    Does this answer your question? [What is the difference between $\* and $@?](https://unix.stackexchange.com/questions/41571/what-is-the-difference-between-and) or [What is the difference between @ and * when referencing bash array values?](https://unix.stackexchange.com/questions/135010/what-is-the-difference-between-and-when-referencing-bash-array-values) – pLumo Feb 07 '22 at 08:10
  • Thanks for the link, I read the 2nd before to create this post. It is similar, but is other scenario. – Manuel Jordan Feb 07 '22 at 12:20

1 Answers1

8

Compare the output of these three loops:

#!/bin/bash

declare -a arr=("this is" "a test" "of bash")

echo "LOOP 1"
for x in ${arr[*]}; do
  echo "item: $x"
done
echo

echo "LOOP 2"
for x in "${arr[*]}"; do
  echo "item: $x"
done
echo

echo "LOOP 3"
for x in "${arr[@]}"; do
  echo "item: $x"
done

The above script will produce this output:

LOOP 1
item: this
item: is
item: a
item: test
item: of
item: bash

LOOP 2
item: this is a test of bash

LOOP 3
item: this is
item: a test
item: of bash

The use of "${array[@]}" in double quotes preserves the items in the array, even if they contain whitespace, whereas you lose that information using either "${array[*]}" or ${array[*]}.


This is explained in the "Arrays" section of the bash(1) man page, which says:

Any element of an array may be referenced using ${name[subscript]}. The braces are required to avoid conflicts with pathname expansion. If subscript is @ or *, the word expands to all members of name. These subscripts differ only when the word appears within double quotes. If the word is double-quoted, ${name[*]} expands to a single word with the value of each array member separated by the first character of the IFS special variable, and ${name[@]} expands each element of name to a separate word...

larsks
  • 32,449
  • 5
  • 54
  • 70
  • Practically the difference applies for iteration and not for the direct output as I shared in the original post - should I assume it is the unique difference? – Manuel Jordan Feb 07 '22 at 20:54
  • Consider to add: echo `"LOOP 4" for x in ${arr[@]}; do echo "item: $x" done` it is such as your Loop 3 but without `""` – Manuel Jordan Feb 07 '22 at 21:08
  • 1
    Yeah, I intentionally skipped that because -- per the quoted docs -- it's going to be identical to the `LOOP 1` output. – larsks Feb 07 '22 at 21:21
  • 1
    W/r/t to your first quesiton, the difference isn't just in iteration. Compare `someprogram "${arr[@]}"` vs any other variant of that expression -- the arguments passed to the program will reflect exactly the differences we see in the above loop examples. – larsks Feb 07 '22 at 21:22
  • 2
    @ManuelJordan `echo` hides the difference. Note that `echo "this is a test of bash"` and `echo "this" "is" "a" "test" "of" "bash"` both print exactly the same thing, despite the actual arguments passed to `echo` being very different (and that difference will matter in almost all situations -- `echo` is the exception here). – Gordon Davisson Feb 07 '22 at 21:57
  • Thanks for the complementary explanation to you both! – Manuel Jordan Feb 07 '22 at 22:50