1

I've recently discovered that you can't pass a null string to a Bash array. This is tricky, as I'm trying to insert an empty string value into an array.

I've noticed that the Bash completion variable COMP_WORDS, however, can contain an empty value.

I've written a dummy completion script to illustrate this, with the debugging options on:

  1 #!/bin/bash
  2 _comp() {
  3     set -xv
  4     for i in ${!COMP_WORDS[@]}; do
  5         echo "<${COMP_WORDS[$i]}>"                                                                                         
  6     done
  7     set +xv
  8     local cur=${COMP_WORDS[$COMP_CWORD]}
  9 
 10     local arr=(apple banana mango pineapple)
 11     COMPREPLY=()
 12     COMPREPLY=($(compgen -W "${arr[*]}" -- $cur))
 13 
 14 }
 15 
 16 complete -F _comp dummy

If I source this file, and then enter the following:

dummy apple   banana

And then if I move the cursor back to the middle space between apple and banana (indicated below by an underscore) ...

dummy apple _ banana

And then if I hit tab, I get the following output from the resulting debug, showing four array elements, 'dummy' 'apple' '' 'banana'

for i in '${!COMP_WORDS[@]}'
+ echo '<dummy>'
<dummy>
+ for i in '${!COMP_WORDS[@]}'
+ echo '<apple>'
<apple>
+ for i in '${!COMP_WORDS[@]}'
+ echo '<>'
<>
+ for i in '${!COMP_WORDS[@]}'
+ echo '<banana>'
<banana>

So the COMP_WORDS array is clearly capable of storing a null string of some kind. Although interestingly, this does not happen if I use a regular for loop, accessing the array elements rather than the indices. I.e., if I change the for loop in the debug section to this ...

for i in ${COMP_WORDS[@]}; do
    echo "<$i>"
done 

Then I get the following debug output showing only three array elements: 'dummy' 'apple' 'banana'

for i in '${COMP_WORDS[@]}'
+ echo '<dummy>'
<dummy>
+ for i in '${COMP_WORDS[@]}'
+ echo '<apple>'
<apple>
+ for i in '${COMP_WORDS[@]}'
+ echo '<banana>'
<banana>

And I've tried echoing the length of the array with ${#COMP_WORDS[@]} - for this input, it shows a length of four. So it clearly does contain four elements, one being a null string.

This seems like really strange behaviour to me. My question is twofold:

  1. What is the explanation for the COMP_WORDS array being able to store null strings when normal arrays apparently cannot?

  2. Why am I unable to see the null string when I use a regular for loop, but I can see it when I access the elements of the array by their indices?

4
  • empty string is not Null \0; arr=( "" "" "" ); echo ${#arr[@]}, result 3 Commented Dec 3, 2020 at 17:10
  • Ah okay. So then I'm wondering - why can I not access these elements using an ordinary for loop?
    – Lou
    Commented Dec 3, 2020 at 17:21
  • 1
    @Lou If you expand the array without double-quotes, word splitting will effectively remove any null elements (and mangle any containing whitespace, and possibly other things). So use for i in "${COMP_WORDS[@]}"; do Commented Dec 3, 2020 at 17:30
  • 1
    Thanks, that makes sense! I must remember to quote everything it seems.
    – Lou
    Commented Dec 3, 2020 at 17:34

1 Answer 1

5

You seem to be confusing the empty string "" with the NULL character \0. They are not the same. You can use empty strings in arrays and variables:

$ a=(aa "" "b")
$ echo "${#a[@]}"
3
$ printf -- '- %s\n' "${a[@]}"
- aa
- 
- b
$ for i in "${a[@]}"; do
> printf '%s\n' "$i"
> done
aa

b

Some of the conditional expressions in Bash even allow testing whether a string is empty:

-z string

True if the length of string is zero.

-n string string

True if the length of string is non-zero.

See also When is double-quoting necessary?

4
  • Oh right, okay. So I guess the question then becomes, why can't I access empty strings in arrays using a regular for loop?
    – Lou
    Commented Dec 3, 2020 at 17:15
  • 1
    You can, you just have to quote the reference to the array in the loop header ("${a[@]}" instead of ${a[@]}).
    – Wieland
    Commented Dec 3, 2020 at 17:26
  • Ah, thanks! Still taking me a while to wrap my head around Bash.
    – Lou
    Commented Dec 3, 2020 at 17:29
  • 2
    If you're new to bash (or, well, even if you're not :-) ), you can use shellcheck.net to check your script for any of the common errors. It's a really valuable tool.
    – Wieland
    Commented Dec 3, 2020 at 17:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .