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.

I'm writing a script and I discovered some unexpected behaviour of uninitialized and unset array variables that I do not understand.

First of all, the length:

giacomo@jack-laptop:~$ echo ${#notset[@]}
0
giacomo@jack-laptop:~$ uninitialized=
giacomo@jack-laptop:~$ echo ${#uninitialized[@]}
1

Why is the uninitialized length 1? Shouldn't it be zero? Is it because a null variable is considered an array of one null element?

This fact leads to some problems. For example suppose I want to create an array, and insert a certain number of things based on the user command line arguments. I thought I could do something like(+):

myarray=

if [ some-condition ]
then
    myarray[${#myarray[@]}]=some-value
fi

if [ some-condition2 ]
then
    myarray[${#myarray[@]}]=some-value2
elif [ some-condition3 ]
then
    myarray[${myarray[@]}]=some-value3
    myarray[${myarray[@]}]=some-value4
fi

But this leaves the first slot to null, which I do not like and also breaks some code that I have written(*), and at this point suppose that I want to see if the array contains any element. How should I do it?

[ -z "${myarray[@]}" ]

Raises an error if the array contains more than an element.

[ -z "$myarray" ]

Fails because the first element is null, even if the array is not empty.

So, how should I control that an array is uninitialized?

And could someone explain what exactly happens when dealing with arrays and unset - uninitialized variables?


(+) I know that I could avoid "declaring" the variable and it would work, but this script will be reviewed by a professor, and he does not like variables being defined at random places.

(*) Before trying this thing I was keeping the length of the array in an other variable, and so I did not have problems. But I'd like to avoid defining this auxiliary variables since I know I can obtain the length without them.

share|improve this question
    
Note that uninitialized is not uninitialized; its first element is the empty string. foo and ${foo[0]} are nearly interchangeable. –  chepner Apr 22 at 18:38
add comment

2 Answers 2

up vote 10 down vote accepted

You can see the difference with declare -p:

unset foo
declare -a foo
declare -p foo
# prints declare -a foo='()'
foo=
declare -p foo
# prints declare -a foo='([0]="")'

If you want to initialize an empty array, the output of the first declare -p is a good hint on the best way to declare it:

declare -a array='()'

(The declare -a part is probably optional, a simple array=() should work just as well.)

If you want to test if an array has 0 elements, use numeric comparison on ${#array[@]}; don't try to do a test -z on the expansion as won't give the correct result in many cases.

share|improve this answer
    
I did not know of declare -p. Thank you for solving my doubts. The only thing that is not clear to me is your last sentence. I always used the ${#array[@]} notation, why did you tell me to not use the other one? –  Bakuriu Oct 26 '12 at 17:37
    
@Bakuriu I was just trying to say that to test if an array is empty, it is easier to test if the count provided by ${#array[@]} is 0 than trying to expand the array contents and testing if the resulting string is empty. –  jw013 Oct 26 '12 at 17:47
add comment

To initialize an empty array, use

array=()

To add a value to the array, use

array+=(value)
share|improve this answer
    
Great, I did not know of this syntax. The only thing is that this requires to use declare -a var to avoid having the null at the beginning. –  Bakuriu Oct 26 '12 at 17:38
    
@Bakuriu: Initialize it as array=(). –  choroba Oct 26 '12 at 17:45
add comment

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.