Reputation: 2136
I am trying to iterate through an n-dimensional space with a series of nested for-loops in bash.
VAR1="a b c d e f g h i"
VAR2="1 2 3 4 5 6 7 8 9"
VAR3="a1 b2 b3 b4 b5 b6"
for i1 in $VAR1; do
for i2 in $VAR2; do
for i3 in $VAR3; do
echo "$i1 $i2 $i3"
done
done
done
Now as I get more dimensions to iterate through, I realize it would be easier/better to be able to specify an arbitrary number of variables to loop through.
If I were using a more sophisticated programming language, I might use recursion to pass a list of lists to a function, pop one list off, iterate through it, recursively calling the function each time through the loop, passing the now reduced list of lists, and assembling the n-tuples as I go.
(I tried to pseudocode what that would look like, but it hurt my head thinking about recursion and constructing the lists.)
function iterate_through(var list_of_lists)
this_list=pop list_of_lists
var new_list = []
for i in this_list
new_list.push(i)
new_list.push(iterate_through(list_of_lists))
# return stuff
# i gave up about here, but recursion may not even be necessary
Anyone have a suggestion for how to accomplish iterating through an arbitrary number of vars in bash? Keeping in mind the goal is to iterate through the entire n-dimensional space, and that iteration is not necessarily part of the solution.
Upvotes: 1
Views: 300
Reputation: 45372
You can use recursion to compute cartesian product
The following script will do the job with variable length input vector :
#!/bin/bash
dim=("a b c d e f g h i" "1 2 3 4 5 6 7 8 9" "a1 b2 b3 b4 b5 b6")
function iterate {
local index="$2"
if [ "${index}" == "${#dim[@]}" ]; then
for (( i=0; i<=${index}; i++ ))
do
echo -n "${items[$i]} "
done
echo ""
else
for element in ${dim[${index}]}; do
items["${index}"]="${element}"
local it=$((index+1))
iterate items[@] "$it"
done
fi
}
declare -a items=("")
iterate "" 0
The following gist will take as input arguments all your dimensions array (with space separated items) : https://gist.github.com/bertrandmartel/a16f68cf508ae2c07b59
Upvotes: 1
Reputation: 13087
If parallel
is acceptable, then one could simplify the nested for
loop as
parallel -P1 echo {1} {2} {3} ::: $VAR1 ::: $VAR2 ::: $VAR3
In the general case, it could be perhaps feasible to first assemble this command and then execute it...
Upvotes: 1