1

When I get the content of an array in a string, I have the 2 solutions bellow :

$ a=('one' 'two')
$ str1="${a[*]}" && str2="${a[@]}"

After, of course, I can reuse my string on the code but how can I know if my variable has only one or several words?

Grégory Roche
  • 162
  • 2
  • 9
  • Minimal research would have found numerous [detailed explanations](http://mywiki.wooledge.org/BashGuide/Arrays). – ghoti Feb 18 '17 at 20:33
  • When I wrote this post, the title isn't the actual title: "The difference between ${array[*]} and ${array[@]} in Bash ?". And for me, there is no confusion between ${array[*]} and ${array[@]}. A person has changed my title and **she hasn't read** my question, that is "How can I know if my variable has only one or several words?" – Grégory Roche Feb 20 '17 at 16:29
  • Your question was posed as a question about array expansion using `[*]` and `[@]`. The linked question explains the difference -- and if you want to know the number of array elements, use `${#a[@]}`. If you want to count words in the expanded array after expansion, I guess the easiest way would be to turn it back into an array and count elements. `s="${a[@]}"; b=($s); echo "${#b[@]}"` – ghoti Feb 21 '17 at 11:29

3 Answers3

2

In both cases, the contents of the array are concatenated to a single string and assigned to the variable. The only difference is what is used to join the elements. With ${a[*]}, the first character of IFS is used. With ${a[@]}, a single space is always used.

$ a=(one two)
$ IFS="-"
$ str1="${a[*]}"
$ str2="${a[@]}"
$ echo "$str1"
one-two
$ echo "$str2"
one two

When expanding $str1 or $str2 without quoting, the number of resulting words is entirely dependent on the current value of IFS, regardless of how the variables were originally defined. "$str1" and "$str2" each expand, of course, to a single word.

chepner
  • 497,756
  • 71
  • 530
  • 681
0

To add to @chepner's great answer: the difference between ${arr[*]} and ${arr[@]} is very similar to the difference between $* and $@. You may want to refer to this post which talks about $* and $@:

What's the difference between $@ and $* in UNIX?

As a rule of thumb, it is always better to use "$@" and "${arr[@]}" than their unquoted or * counterparts.

Community
  • 1
  • 1
codeforester
  • 39,467
  • 16
  • 112
  • 140
  • 1
    I wouldn't say it is *better* to use `@`, rather it is more likely that `@` does what you want. – chepner Feb 18 '17 at 20:09
  • 1
    One important difference (although I think it is fixed in a recent Bash version) : `"$@"` expands to nothing if there are no arguments, and `"${arr[@]}"` causes an error if the array is empty. This is so annoying... You have to use `${arr[@]+"${arr[@]}"}` instead to get the same result (often useful in `for` loops, for instance). – Fred Feb 18 '17 at 21:40
  • @Fred I can't seem to reproduce any error with `"${foo[@]}"` for `foo` either unset or empty, at least not in `bash` 3.2 or 4.4. Was it a regression in an earlier 4.x release? – chepner Feb 18 '17 at 23:29
  • @chepner Sorry, I forgot to mention that this was with `set -u`. I use that systematically in all my scripts, so for me what `set -u` does is my "mental default". `"$@"` expands without errors even when there are no positional parameters under `set -u`. – Fred Feb 19 '17 at 00:06
0

"${a[*]}" expands to one string for all entries together and "${a[@]}" expands to one string per entry.

Assume we had a program printParameters, which prints for each parameter ($1, $2, and so on) the string my ... parameter is ....

>_ a=('one' 'two')

>_ printParameters "${a[*]}"
my 1. parameter is one two

>_ printParameters "${a[@]}"
my 1. parameter is one
my 2. parameter is two

If you would expand the array manually, you would write
${a[*]} as "one two" and
${a[@]} as "one" "two".

There also differences regarding IFS and so on (see other answers). Usually @ is the better option, but * is way faster – use the latter one in cases where you have to deal with large arrays and don't need separate arguments.

By the way: The script printParameters can be written as

#! /bin/bash
argIndex=0
for argValue in "$@"; do
    echo "my $((++i)). argument is $argValue"
done

It's very useful for learning more about expansion by try and error.

Socowi
  • 25,550
  • 3
  • 32
  • 54