In bash, the conditional expression with the unary test -v myvariable
tests wether the variable myvariable
has been set. Note that myvariable
should not be expanded by prefixing it with a dollar, so not $myvariable
.
Now I find that for array elements the conditional expression -v myarray[index]
works well too, without the full expansion syntax ${myarray[$index]}
. Try this:
myarray[2]=myvalue
for i in 1 2 3
do
[ -v myarray\[i] ] && echo element $i is set
done
(note the escape \[
to prevent globbing, as alternative to using quotes)
gives the desired output:
element 2 is set
Question Is this behaviour safe to use aka is this documented behaviour?
Addendum After reading the answer https://unix.stackexchange.com/a/677920/376817 of Stéphane Chazelas, I expanded my example:
myarray[1]=val myarray[2]=val myarray[3]=val myarray[4]=val myarray[5]=val myarray[6]="" myarray[2]=""
unset myarray[3] myarray[4] myarray[5]
touch myarray4 myarrayi
myarray4=val myarrayi=val
then
for i in {0..7}; do [ -v myarray\[i] ] && echo element $i is set; done
gives
element 1 is set
element 2 is set
element 6 is set
Without quoting or escaping the index expression [i]
:
for i in {0..7}; do [ -v myarray[i] ] && echo element $i is set; done
gives
element 0 is set
element 1 is set
element 2 is set
element 3 is set
element 4 is set
element 5 is set
element 6 is set
element 7 is set
The same with the variable myarrayi
unset :
unset myarrayi
for i in {0..7}; do [ -v myarray[i] ] && echo element $i is set; done
gives
%nothing%
And finally with expansion of the index as $i
(still without quoting or escaping the bracket) :
for i in {0..7}; do [ -v myarray[$i] ] && echo element $i is set; done
it gives
element 1 is set
element 2 is set
element 4 is set
because
ls -l myarray*
shows
-rw-rw-r-- 1 me us 0 nov 17 15:37 myarray4
-rw-rw-r-- 1 me us 0 nov 17 15:37 myarrayi
-v
. I reran my example with a filemyarrayi
, and a variablemyarrayi
set or unset, and the globbing occurs as you say. I edited the example. Also thanks for explaining whymyarray[$i]
gives the same result asmyarray[i]
. But do you answer my question? You say that my code works; I tested it, so I knew that. But is it documentated that the-v
unary operator also works on thename[index]
construct, and not only on a simplename
? I do not like to use undocumented features. That is my question, that I feel you do not answer. – db-inf Nov 17 '21 at 14:19info
book is the official documentation (you can also find it in other formats derived from the same source like the HTML one I linked). Ultimately, you can look at the source to see how it's done and see if the behaviour is intentional or an accident of implementation that may go away in the future. In any case, Chet Ramey will decide whether to keep it in the future or not, whether it's documented or not. As it's not clearly documented, he could decide to drop it, but that would upset a number of users. So most likely, you'd still be able to use BASH_COMPAT=5.1 to use it then. – Stéphane Chazelas Nov 17 '21 at 14:35-v
unary test turns out to be for array checking. So yes, it is on purpose that-v 'myarray[i]'
gives the result as is. However, between my current version 4.4(.18) and the most recent 5.1.8 there has been a lot of change to the code: it is not stable yet, and the lack of detailed documentation may be a consequence thereof. – db-inf Nov 17 '21 at 20:45-v 'myarray[@]'
and-v 'myarray[@]'
return true when any array element is set. I tested it in 4.4.18 and it works as such, but to me that is not clear from a quick look at the code. Also, new in the 5.1.8 code is that it allows to test for the positional parameters as well:-v 1
tests wether positional parameter 1 (that elsewhere you refer to as$1
) is set. I tested that in my bash 4.4.18, and it does not work. – db-inf Nov 17 '21 at 20:49test -v 1
mentioned in the release notes. See edit for more there. – Stéphane Chazelas Nov 18 '21 at 07:37