Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

This lines of a Bash (4.0) Script

klang=([string_0]='element_0' [string_1]='element_1' [string_2]='element_2')
echo "${klang[*]}"     # should output the all set elements
echo "${#klang[*]}"    # should output the number of set elements

returns (for some reason):

element_2
1

There are no other commands set in this script and I am really new in Bash scripting. What happened to the other elements (Element_0 and Element_1)? This really worked perfectly with indexed arrays and numbers and everything, but doesn't work with text – well except for one element which is a bit less than I asked for… Where did I miss something?

share|improve this question

2 Answers 2

up vote 1 down vote accepted

If you don't declare the variable as an associative array, then the

klang=([string_0]='element_0' [string_1]='element_1' [string_2]='element_2')

is taken as a normal array assignment (though note that in bash and ksh93, normal arrays are not really normal arrays, they're more sparse arrays or associative arrays with keys limited to positive integers).

In bash, for a normal array, keys are evaluated as arithmetic expressions. As an arithmetic expression, string_0 evaluates to the content of $string_0, and if that's empty, to 0. So the above is likely to be the same as:

klang=([0]='element_0' [0]='element_1' [0]='element_2')

So, that's the same as defining ${klang[0]} (which is the same as $klang) 3 times.

That contrasts with ksh93 arrays (which bash mostly copied), where the a=([x]=y) syntax is only supported for associative arrays and would automatically create an associative array when used.

zsh associative arrays (which predate bash ones by decades) are different again. zsh normal arrays are normal arrays, zsh doesn't support the bogus a=([x]=y) syntax. In zsh, you have to declare associative arrays before defining them, and they are defined as:

normal_array=(val1 val2 val3)
typset -A associative_array
associative_array=(key1 val1 key2 val2)
associative_array+=(key3 val3...)

And $associative_array expends to the non-empty values like for normal arrays (in undefined order), and "$associative_array[@]}" to all the values like for normal arrays. ${(k)associative_array} for the non-empty keys, "${(k@)associative_arrays}" for all the keys, "${(kv@)associative_array}" for the keys and values, so you can print the content of an associative array with:

printf '%s => %s\n' "${(@kv)associative_array}"

That also means the copying an associative array is a lot less cumbersome than with ksh93/bash:

typeset -A B
B=("${(kv@)A}")

as opposed to:

unset B
typeset -A B
for k in "${!A[@]}"; do B[$k]=${A[$k]}; done
share|improve this answer

You need to first declare your variable (klang here) to be an associative array with bash:

$ declare -A klang
$ klang=([string_0]='element_0' [string_1]='element_1' [string_2]='element_2')
$ echo "${klang[*]}"
element_2 element_0 element_1
$ echo "${#klang[*]}"
3

Associative arrays were introduced with bash version 4.0.

They were first implemented by ksh93, with which this issue doesn't appear.

share|improve this answer
    
Facepalm! Of course!!! –  erch Jan 12 at 23:36
    
just another question (candidate for facepalm?): What is the way to get, say, the second element (element_1) only - or is this only available for indexed arrays? –  erch Jan 12 at 23:56
1  
Shell associative arrays are unordered by design so there is no 'second element' to begin with. –  jlliagre Jan 13 at 1:23
    
This explains a lot… and is really helpful - thanks a lot! –  erch Jan 13 at 1:41

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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