Bash – Disadvantages of assigning an array to a variable like this: array2=(“${array1[@]}”)

arraybash

I can copy an array to another like this:

array2=("${array1[@]}")

One of the disadvantages of this approach is that the indices will not be preserved. For example: if array1 have three elements with indices 1 and 2 and 5, then array2 will have the indices 1 and 2 and 3.

Are there other disadvantages?

Best Answer

Well, "${array[@]}" gives you the values of the array, that's all. I don't think it should have any problems with that.

But it doesn't give you anything outside the values, like indexes (as you mention), or other attributes. Bash arrays could be read-only, or have the integer or upper/lowercase attributes. The same of course goes for associative arrays: the result of that assignment would be a regular indexed array, but losing the indexes would be the bigger issue. The attributes would probably be easy, you'd probably know what attributes you've set on the array.

An assignment like array2=("${array1[@]}") would remove all the original values of array2, so there's no problem with leftover data. The attributes of array2 would be kept though, and if it's set an integer array, the values of array2 would be taken as arithmetic expressions. (Same as in a="1 + 3"; declare -i b=$a; echo $b, which prints "4".)

To copy the indexes too, you'd need use a loop (and set the attributes manually):

# declare -A arr2    # if it was an associative array
arr2=()              # clear the target
for k in "${!arr[@]}" ; do arr2[$k]=${arr[$k]} ; done 

Or, to get an exact copy, attributes and all, the output of declare -p is usable as input to the shell, so this should copy ai1 to ai2 with all keys and attributes:

declare -Ai ai1=([foo]=123 [$'a tricky key\n']=456)
definition=$(declare -p ai1)
eval "${definition/ ai1/ ai2}"

String operations like ${var/pat/repl} work on all values. I don't think you should have any other issues with that either. Though I do think the asterisk in your pattern is misplaced as ${var/pat/repl} along with ${var##pat} take the longest match, so "${var/#prefix*/}" would clear the whole value.

You probably want "${myArray[@]#unwanted-prefix}" instead.

Related Question