The main reason why your second attempt doesn't work is because you're trying to solve a different problem using the same solution.
In the first data set you have two numeric indexed arrays where the keys have no meaning other than possibly the order they appear in, and their values are what really matters. I interpreted that to mean you wanted to linear concatenate those values to a new array with a new index which discards the previous keys but maintains the original order of the elements as well as the order you passed them in.
The second data set you have two associative indexed arrays where the keys are the values and the values are really just placeholders. I noticed that you used numeric keys, which if you chose to keep using numeric indexed arrays would allow you to preserve both the order of the values and the order of the keys, on the assumption that you want the keys in ascending order...
So then for solving these problems I have 3 convenience functions I've written which use declare and eval to accelerate joining/merging large arrays rather than using loops to assign each. They also take a variable number of arrays as argument so you can join / merge / dump as many of them as you please.
NOTE: I changed the value/key "30" out for "30 30" to demonstrate how a string would behave differently than a number in some circumstances.
join_arrays(){
# <array> [<array> ...] <destination array>
# linear concatenates the values, re-keys the result.
# works best with indexed arrays where order is important but index value is not.
local A_;
while (( $# > 1 )); do
A_+="\"\${$1[@]}\" ";
shift;
done
eval "$1=($A_)";
}
# This works by building and running an array assignment command
# join_array a1 a2 a3 becomes a3=("${a1[@]" "$a2[@]" );
merge_arrays(){
# <array> [<array> ...] <destination array>
# merges the values, preserves the keys.
# works best with assoc arrays or to obtain union-like results.
# if a key exists in more than one array the latter shall prevail.
local A_ B_;
while (( $# > 1 )); do
B_=`declare -p $1`;
B_=${B_#*=??};
A_+=${B_::-2}" ";
shift;
done
eval "$1=($A_)";
}
# this crops the output of declare -p for each array
# then joining them into a single large assignment.
# try putting "echo" in front of the eval to see the result.
dump_arrays(){
# <array> [<array> ...]
# dumps array nodes in bash array subscript assignment format
# handy for use with array assignment operator. Preseves keys.
# output is a join, but if you assign it you obtain a merge.
local B_;
while (( $# > 0 )); do
B_=`declare -p $1`;
B_=${B_#*=??};
printf "%s " "${B_::-2}";
shift;
done
}
# same as above but prints it instead of performing the assignment
# The data sets, first the pair of indexed arrays:
declare -a array1=( 5 10 15 );
declare -a array2=( 20 25 "30 30" );
# then the set of assoc arrays:
declare -a array3=( [5]=true [10]=true [15]=true );
declare -a array4=( [20]=true [25]=true ["30 30"]=true );
# show them:
declare -p array1 array2 array3 array4;
# an indexed array for joins and an assoc array for merges:
declare -a joined;
declare -A merged;
# the common way to join 2 indexed arrays' values:
echo "joining array1+array2 using array expansion/assignment:";
joined=( "${array1[@]}" "${array2[@]}" );
declare -p joined;
declare -a joined='([0]="5" [1]="10" [2]="15" [3]="20" [4]="25" [5]="30 30")'
# this does exactly the same thing, mostly saves me from typos ;-)
echo "joining array1+array2 using join_array():";
join_arrays array1 array2 joined;
declare -p joined;
declare -a joined='([0]="5" [1]="10" [2]="15" [3]="20" [4]="25" [5]="30 30")'
# this merges them by key, which is inapropriate for this data set
# But I've included it for completeness to contrast join/merge operations
echo "merging array1+array2 using merge_array():";
merge_arrays array1 array2 merged;
declare -p merged;
declare -A merged='([0]="20" [1]="25" [2]="30 30" )'
# Example of joining 2 associative arrays:
# this is the usual way to join arrays but fails because
# the data is in the keys, not the values.
echo "joining array3+array4 using array expansion/assignment:"
joined=( "${array3[@]}" "${array4[@]}" );
declare -p joined;
declare -a joined='([0]="true" [1]="true" [2]="true" [3]="true" [4]="true" [5]="true")'
# and again, a join isn't what we want here, just for completeness.
echo "joining array3+array4 using join_array():";
join_arrays array3 array4 joined;
declare -p joined;
declare -a joined='([0]="true" [1]="true" [2]="true" [3]="true" [4]="true" [5]="true")'
# NOW a merge is appropriate, because we want the keys!
echo "merging array3+array4 using merge_array():"
merge_arrays array3 array4 merged;
declare -p merged;
declare -A merged='([25]="true" [20]="true" ["30 30"]="true" [10]="true" [15]="true" [5]="true" )'
# Bonus points - another easy way to merge arrays (assoc or indexed) by key
# Note: this will only work if the keys are numeric...
join_arrays array1 array2 joined;
# error expected because one keys is "30 30" ...
eval joined+=(`dump_arrays merged`);
bash: 30 30: syntax error in expression (error token is "30")
declare -p joined
declare -a joined='([0]="5" [1]="10" [2]="15" [3]="20" [4]="25" [5]="30 30" [20]="true" [25]="true")'
# Note: assoc arrays will not be sorted, even if keys are numeric!
join_arrays array1 array2 joined;
eval merged+=(`dump_arrays joined`);
declare -p merged
declare -A merged='([25]="true" [20]="true" ["30 30"]="true" [10]="true" [15]="true" [0]="5" [1]="10" [2]="15" [3]="20" [4]="25" [5]="true30 30" )'
Final Note: above you can see Key [5] has the values of the two source arrays' key [5] concatenated because I used the += operator. If you're just using it for merging lists of flags, it's safe, but for merging lists of meaningful values with possible key collisions, its better to stick to the merge_array() function.
[key]=value
items for each key. I don't know of any such expansion. The closest I can think of is whatdeclare -p
gives you (which you would need to massage to use). – Seringapatam