user1638962
user1638962

Reputation: 571

Copying a Bash array fails

Assigning arrays to variables in Bash script seems rather complicated:

a=("a" "b" "c")
b=$a

echo ${a[0]} 
echo ${a[1]}

echo ${b[0]} 
echo ${b[1]} 

leads to

a 
b 
a
   

instead of

a
b
a
b

Why? How can I fix it?

Upvotes: 49

Views: 51121

Answers (2)

kojiro
kojiro

Reputation: 77137

If you want to copy a variable that holds an array to another name, you do it like this:

a=('a' 'b' 'c')
b=( "${a[@]}" )

Upvotes: 79

Chad Skeeters
Chad Skeeters

Reputation: 1488

Why?

If a is an array, $a expands to the first element in the array. That is why b in your example only has one value. In bash, variables that refer to arrays aren't assignable like pointers would be in C++ or Java. Instead variables expand (as in Parameter Expansion) into strings and those strings are copied and associated with the variable being assigned.

How can I fix it?

To copy a sparse array that contains values with spaces, the array must be copied one element at a time by the indices - which can be obtained with ${!a[@]}.

declare -a b=()
for i in ${!a[@]}; do
    b[$i]="${a[$i]}"
done

From the bash man page:

It is possible to obtain the keys (indices) of an array as well as the values. ${!name[@]} and ${!name[*]} expand to the indices assigned in array variable name. The treatment when in double quotes is similar to the expansion of the special parameters @ and * within double quotes.

Here's a script you can test on your own:

#!/bin/bash

declare -a a=();
a[1]='red hat'
a[3]='fedora core'

declare -a b=();

# Copy method that works for sparse arrays with spaces in the values.
for i in ${!a[@]}; do
    b[$i]="${a[$i]}"
done

# does not work, but as LeVar Burton says ...
#b=("${a[@]}")

echo a indicies: ${!a[@]}
echo b indicies: ${!b[@]}

echo "values in b:"
for u in "${b[@]}"; do
    echo $u
done

Prints:

a indicies: 1 3
b indicies: 1 3  # or 0 1 with line uncommented
values in b:
red hat
fedora core

This also works for associative arrays in bash 4, if you use declare -A (with capital A instead of lower case) when declaring the arrays.

Upvotes: 24

Related Questions