In Bash I can instantiate an empty array a
using a=()
. I can then append elements using e.g. a[${#a[@]}]="new element"
where ${#a[@]}
gives the number of elements in a
. In a Bash function:
fun() {
local a=()
echo "size: ${#a[@]}"
echo "content: >${a[@]}<"
}
fun # run the function
In modern Bash versions, this prints
size: 0
content: >< # empty
For Bash 3.0, though, I get
size: 1
content: >()<
It seems as though a
is not really an array but rather a string with the value ()
.
I can get the usual behavior if I remove the local
keyword. This suggests that mixing local
and array initialization ()
is not supported in Bash 3.0.
Is this expected?
I am writing a large Bash script and seek to be compatible with all Bash versions down to 3.0. I can think of two solutions, neither of which are nice:
a
if this is equal to ()
, once a
has been fully populated with elements. This (somewhat surprisingly) works because even when a
is the string ()
, array appends a[${#a[@]}]="new element"
still works, effectively converting a
to an array the original string value ()
as the first element.Any better ideas?
To test things out with Bash 3.0, I use Docker:
docker run --rm bash:3.0 bash -c 'fun() { local a=(); echo "size: ${#a[@]}"; echo "content: >${a[@]}<"; }; fun'
The problem goes away already wih bash:3.1
.
Assignment of an "empty" array to a name doesn't actually define a variable at all; it just sets the array attribute of the name. Some options:
declare -a a
local a; a=()
local -a a
What you are seeing appears to be a bug in Bash 3.0's implementation of local
(subsequently fixed in Bash 3.1) that doesn't properly recognize array assignments.