Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copying a Bash array fails

Tags:

arrays

bash

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?

like image 682
user1638962 Avatar asked Sep 06 '12 15:09

user1638962


People also ask

How do you copy an array in Bash?

Note: when copying associative arrays, the destination must already exist as an associative array. If not, array_copy() will create it as a standard array and try to interpret the key names from the associative source as arithmetic variable names, with ugly results.

How do you append to an array in Bash?

To append element(s) to an array in Bash, use += operator. This operator takes array as left operand and the element(s) as right operand. The element(s) must be enclosed in parenthesis. We can specify one or more elements in the parenthesis to append to the given array.


2 Answers

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[@]}" ) 
like image 163
kojiro Avatar answered Oct 02 '22 05:10

kojiro


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.

like image 31
Chad Skeeters Avatar answered Oct 02 '22 03:10

Chad Skeeters