25

This Bash guide says:

If the index number is @ or *, all members of an array are referenced.

When I do this:

LIST=(1 2 3)
for i in "${LIST[@]}"; do
  echo "example.$i"
done

it gives the desired result:

example.1
example.2
example.3

But when I use ${LIST[*]}, I get

example.1 2 3

instead.

Why?

Edit: when using printf, @ and * actually do give the same results.

4
  • It seems to work for me. I tried both @ and * and it seems to produce the same result both the times. What shell you are using? Run echo $SHELL and paste the output to your question.
    – Ramesh
    Jun 7 '14 at 14:26
  • My example was wrong, this actually happens only with echo, not with printf, I just noticed.
    – arjan
    Jun 7 '14 at 14:36
  • possible duplicate of What is the difference between $* and $@?
    – goldilocks
    Jun 7 '14 at 17:13
  • @goldilocks The other question is about $* and $@. Though, the answer would be similar and one question could be considered a subset of the other, they are different questions. Jun 7 '14 at 19:31
22

The difference is subtle; "${LIST[*]}" (like "$*") creates one argument, while "${LIST[@]}" (like "$@") will expand each item into separate arguments, so:

LIST=(1 2 3)
for i in "${LIST[@]}"; do
    echo "example.$i"
done

will deal with the list (print it) as multiple variables.

But:

LIST=(1 2 3)
for i in "${LIST[*]}"; do
    echo "example.$i"
done

will deal with the list as one variable.

5
  • Do you know where the difference between echo and printf comes from? Because with printf in the for loop, the * list reference is treated as multiple variables.
    – arjan
    Jun 7 '14 at 14:45
  • What does it mean for something to be dealt with as one versus multiple variables? I wonder if you could provide a practical example to illustrate the difference.
    – fraxture
    Mar 22 '19 at 13:47
  • Wow, it's worth while mentioning that when you do the one with the star that it separates the values by the value of "IFS". For example, try this: IFS="/" && LIST=(1 2 3); for i in "${LIST[*]}"; do echo "$i"; done; and you should get "1/2/3". Hell, if you couldn't remember any other method you could use this replace a character now that I think about it by setting IFS to the before character, splitting it using read -a <<< '$string", and then changing the IFS to the replacement before looping through and reconstructing it. Rather brute force but still... Sep 15 '20 at 9:35
  • Hey, check it out! i.imgur.com/WYYtdvQ.png. It totally worked. Script is: IFS=" " && read -a arrBefore; IFS="/" && for i in "${arrBefore[*]}"; do echo "$i"; done; Sep 15 '20 at 9:54
  • Yes and note that it is the surrounding double quotes that in turn preserves the "${LIST[*]}" as "1 2 3" and prevents it from getting split one more time into "1" "2" "3". Always double quote variable expansions UNLESS YOU WANT a spaces in their expanded value to cause splitting.
    – conny
    Mar 25 at 9:46
1

Using [*] will create a single string, with each element of your array delimited by the first character of $IFS (a space by default).

Using [@] will create a list.

Examples:

Creating an array:

$ list=( a b "big fish" c d )

Printing each element individually:

$ printf 'data: ---%s---\n' "${list[@]}"
data: ---a---
data: ---b---
data: ---big fish---
data: ---c---
data: ---d---

Creating a single string and printing that:

$ printf 'data: ---%s---\n' "${list[*]}"
data: ---a b big fish c d---

Again, but with a custom delimiter:

$ IFS='/'
$ printf 'data: ---%s---\n' "${list[*]}"
data: ---a/b/big fish/c/d---

Note that using these expansions without double quotes rarely makes sense.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.