如何在 Bash 中复制数组?

我有一个应用程序数组,初始化如下:

depends=$(cat ~/Depends.txt)

当我尝试解析列表并将其复制到新数组时,

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

发生的情况是,只有 Depend 的第一个元素依赖于 newDepend。

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

^ ^ 这只会输出一个结果。所以我想知道为什么我的 for 循环只移动了第一个元素。整个清单最初取决于,所以不是那个,但我没有主意了。

87635 次浏览

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.

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.

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

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

Starting with Bash 4.3, you can do this

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


$ declare -n golf=alpha


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

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.

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
"
}

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

This works easily.

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).

Managed to copy an array into another.

firstArray=()
secondArray=()


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


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


for element in "${secondArray[@]}"; do
echo "${element}"
done
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.