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:
$ echo ${#notset[@]}
0
$ uninitialized=
$ 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.
Best Answer
You can see the difference with
declare -p
: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:(The
declare -a
part is probably optional, a simplearray=()
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 atest -z
on the expansion as won't give the correct result in many cases.