1

I found the following two loops yield the same output. Can you help me to understand what the differences are between the @ and * in this particular case?

#!/bin/bash

ips=(8.8.8.8 8.8.4.4)

for ip in ${ips[@]}; do
    echo $ip
done

for ip in ${ips[*]}; do
    echo $ip
done

They both yield the same result:

8.8.8.8
8.8.4.4
Anthon
  • 79,293
Qian Chen
  • 799

2 Answers2

4

Bash Man page quote

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.

When there are no array members, ${name[@]} expands to nothing. If the double-quoted expansion occurs within a word, the expansion of the first parameter is joined with the beginning part of the original word, and the expansion of the last parameter is joined with the last part of the original word.

Which means:

munai@munai-devops:~$ declare -a array
munai@munai-devops:~$ array=(1 2 3)
munai@munai-devops:~$ bakIFS=$IFS
munai@munai-devops:~$ IFS=","
munai@munai-devops:~$ echo "${array[*]}"
1,2,3
munai@munai-devops:~$ echo "${array[@]}"
1 2 3
1

As you've notice, there is no difference between the two - that is when the arrays are not quoted.

"${arr[*]}" expands the array to one element, whereas "${arr[@]}" expands each element but preserving whitespace (IFS).

The first array won't change but the second will have the output of:

8.8.8.8 8.8.4.4