How to copy an array in Bash?

ArraysBashCopy

Arrays Problem Overview


I have an array of applications, initialized like this:

depends=$(cat ~/Depends.txt)

When I try to parse the list and copy it to a new array using,

for i in "${depends[@]}"; do
   if [ $i #isn't installed ]; then
      newDepends+=("$i")
   fi
done

What happens is that only the first element of depends winds up on newDepends.

for i in "${newDepends[@]}"; do
   echo $i
done

^^ This would output just one thing. So I'm trying to figure out why my for loop is is only moving the first element. The whole list is originally on depends, so it's not that, but I'm all out of ideas.

Arrays Solutions


Solution 1 - Arrays

a=(foo bar "foo 1" "bar two")  #create an array
b=("${a[@]}")                  #copy the array in another one 

for value in "${b[@]}" ; do    #print the new array 
echo "$value" 
done   

Solution 2 - Arrays

The simplest way to copy a non-associative array in bash is to:

arrayClone=("${oldArray[@]}")

or to add elements to a preexistent array:

someArray+=("${oldArray[@]}")

Newlines/spaces/IFS in the elements will be preserved.

For copying associative arrays, Isaac's solutions work great.

Solution 3 - Arrays

The solutions given in the other answers won't work for associative arrays, or for arrays with non-contiguous indices. Here are is a more general solution:

declare -A arr=([this]=hello [\'that\']=world [theother]='and "goodbye"!')
temp=$(declare -p arr)
eval "${temp/arr=/newarr=}"

diff <(echo "$temp") <(declare -p newarr | sed 's/newarr=/arr=/')
# no output

And another:

declare -A arr=([this]=hello [\'that\']=world [theother]='and "goodbye"!')
declare -A newarr
for idx in "${!arr[@]}"; do
    newarr[$idx]=${arr[$idx]}
done

diff <(echo "$temp") <(declare -p newarr | sed 's/newarr=/arr=/')
# no output

Solution 4 - Arrays

Try this: arrayClone=("${oldArray[@]}")

This works easily.

Solution 5 - Arrays

You can copy an array by inserting the elements of the first array into the copy by specifying the index:

#!/bin/bash

array=( One Two Three Go! );
array_copy( );

let j=0;
for (( i=0; i<${#array[@]}; i++)
do
    if [[ $i -ne 1 ]]; then # change the test here to your 'isn't installed' test
        array_copy[$j]="${array[$i]}
        let i+=1;
    fi
done

for k in "${array_copy[@]}"; do
    echo $k
done

The output of this would be:

One
Three
Go!

A useful document on bash arrays is on TLDP.

Solution 6 - Arrays

array_copy() {
    set -- "$(declare -p $1)" "$2"
    eval "$2=${1#*=}"
}

# Usage examples:

these=(apple banana catalog dormant eagle fruit goose hat icicle)
array_copy these those
declare -p those

declare -A src dest
source=(["It's a 15\" spike"]="and it's 1\" thick" [foo]=bar [baz]=qux)
array_copy src dest
declare -p dest

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.

Isaac Schwabacher's solution is more robust in this regard, but it can't be tidily wrapped up in a function because its eval step evaluates an entire declare statement and bash treats those as equivalent to local when they're inside a function. This could be worked around by wedging the -g option into the evaluated declare but that might give the destination array more scope than it's supposed to have. Better, I think, to have array_copy() perform only the actual copy into an explicitly scoped destination.

Solution 7 - Arrays

Problem is to copy array in function to be visible in parent code. This solution works for indexed arrays and if before copying are predefined as declare -A ARRAY, works also for associative arrays.

function array_copy
# $1 original array name
# $2 new array name with the same content
{
    local INDEX
    eval "
        for INDEX in \"\${!$1[@]}\"
        do
            $2[\"\$INDEX\"]=\"\${$1[\$INDEX]}\"
        done
    "
}

Solution 8 - Arrays

Starting with Bash 4.3, you can do this

$ alpha=(bravo charlie 'delta  3' '' foxtrot)

$ declare -n golf=alpha

$ echo "${golf[2]}"
delta  3

Solution 9 - Arrays

Managed to copy an array into another.

firstArray=()
secondArray=()

firstArray+=("Element1")
firstArray+=("Element2")

secondArray+=("${firstArray[@]}")

for element in "${secondArray[@]}"; do
  echo "${element}"
done

Solution 10 - Arrays

I've found that this works for me (mostly :)) ...

eval $(declare -p base | sed "s,base,target,")

extending the sed command to edit any switches as necessary e.g. if the new structure has to be writeable, to edit out read-only (-r).

Solution 11 - Arrays

I've discovered what was wrong.. My if isn't installed test is two for loops that remove excess characters from file names, and spits them out if they exist on a certain web server. What it wasn't doing was removing a trailing hyphen. So, when it tested it online for availability, they were parsed out. Because "file" exists, but "file-" doesn't.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKyle R.View Question on Stackoverflow
Solution 1 - Arraysuser1088530View Answer on Stackoverflow
Solution 2 - ArraysniieaniView Answer on Stackoverflow
Solution 3 - ArraysIsaac SchwabacherView Answer on Stackoverflow
Solution 4 - ArraysmaheshkView Answer on Stackoverflow
Solution 5 - Arraysimp25View Answer on Stackoverflow
Solution 6 - ArraysflabdabletView Answer on Stackoverflow
Solution 7 - ArraysHiroView Answer on Stackoverflow
Solution 8 - ArraysZomboView Answer on Stackoverflow
Solution 9 - ArraysAndrea BriffaView Answer on Stackoverflow
Solution 10 - Arrayspointo1dView Answer on Stackoverflow
Solution 11 - ArraysKyle R.View Answer on Stackoverflow