Eine faktorielle Schleife durch ein Array
Ich habe eine Reihe von Hosts.
a_hosts=( "host1.q.d.n",
"host2.q.d.n",
"host3.q.d.n",
...
"hostN.q.d.n"
)
Ich muss eine bestimmte Datei auf jedem Host mit derselben Datei auf allen anderen Hosts vergleichen.
diff host1.file host2.file
diff host1.file host3.file
...
diff host1.file hostN.file
diff host2.file host3.file
...
diff host2.file hostN.file
...etc.
Ich habe Ideen, die auf dieser Lösung basieren , aber ich stütze mich immer wieder in eine Ecke, wenn ich versuche, mich loopN-1 innerhalb einer Schleife durchzuschleifen loopN. Ich denke fast, ich muss das Array duplizieren und die beiden Arrays synchronisieren. Aber das ist noch eine Schleife.
Hat jemand eine elegante Lösung für diese Art der Schleifenmanipulation gefunden?
EDIT 1:
Ich experimentiere damit.
# Create two loop arrays.
a_outer_loop=a_hosts
a_inner_loop=a_hosts
# Iterate through outer loop.
for s_fqdn1 in ${a_outer_loop[@]} do # Pop the first item of the inner loop. (Index 0) a_inner_loop=( ${a_inner_loop[@]:1:} )
# Loop through the popped inner loop.
for s_fqdn2 in ${a_inner_loop[@]}
do
diff s_fqdn1.file s_fqdn2.file
done
done
EDIT 2:
Bestätigen Sie! Entschuldigung, meine Schuld für die Vereinfachung meines Beispiels. Wenn meine Liste der Hosts wirklich war host1, host2..., hostNwäre dies ein viel einfacheres Problem sein. Leider habe ich verschiedene Arten von FQDNs in verschiedenen Bereichen zu behandeln, sodass keine Lösung so einfach ist, wie host$isie funktionieren wird. Die gute Nachricht ist: Ich glaube, ich habe etwas, das funktionieren wird.
Antworten
Schleife mit dem Index der Elemente und dann Versatz des Arrays mit diesem Index in der verschachtelten Schleife:
#! /bin/bash
a_hosts=( "host1.q.d.n"
"host2.q.d.n"
"host3.q.d.n"
...
"hostN.q.d.n"
)
for i in "${!a_hosts[@]}" do host1=${a_hosts[i]}
for host2 in "${a_hosts[@]:i+1}" do echo "$host1" "$host2"
done
done
${!a_hosts[@]}- die Indizes aller Elemente im Array${a_hosts[@]:i+1}- Das Array beginnt mit dem Offseti+1(die arithmetische Erweiterung wird für den Array-Index durchgeführt).
Ausgabe mit dem Beispiel (ohne Komma):
% bash foo.sh
host1.q.d.n host2.q.d.n
host1.q.d.n host3.q.d.n
host1.q.d.n ...
host1.q.d.n hostN.q.d.n
host2.q.d.n host3.q.d.n
host2.q.d.n ...
host2.q.d.n hostN.q.d.n
host3.q.d.n ...
host3.q.d.n hostN.q.d.n
... hostN.q.d.n
Muru und dafydd gaben Ihnen bereits die eleganten Ansätze. Hier ist die Brute Force One:
#! /bin/bash
a_hosts=( "host1.q.d.n"
"host2.q.d.n"
"host3.q.d.n"
"hostN.q.d.n"
)
for((i=0;i<${#a_hosts[@]};i++)); do for((k=$i+1;k<${#a_hosts[@]};k++)); do diff <(ssh "${a_hosts[$i]}" cat /path/to/file) \ <(ssh "${a_hosts[$k]}" cat /path/to/file)
done
done
Dies funktioniert in Bash 4. Das Beste daran ist, dass es für den Inhalt des Quell-Arrays völlig unabhängig ist.
Stellen Sie Ihr Quellarray ein.
a_fqdns=( "h1.q.d.n" "h5.r.d.n" "i21.s.d.n" ... )
Pop für die äußere Schleife das letzte Element , da die entsprechende innere Schleife für dieses Element leer wäre.
a_outer_loop=( ${a_fqdns[@]} ) unset a_outer_loop[${#a_fqdns[@]}-1]
a_inner_loop=( ${a_fqdns[@]} ) for s_fqdn1 in ${a_outer_loop[@]}
do
echo ${s_fqdn1}
Pop das erste Element (Index 0) aus der inneren Schleife. Dies führt dazu, dass die innere Schleife für jede Iteration der äußeren Schleife um ein Element (Index 0) verkleinert wird. Beachten Sie, dass dies a_outer_loop[i]den gleichen Wert wie a_inner_loop[0]für jede Iteration von hat a_outer_loop.
Funktioniert auch unset 'a_inner_loop[0]'hier nicht. unsetZeigt Index 0 nicht an, sondern ändert nur den Wert von Index 0 in eine leere Zeichenfolge.
a_inner_loop=( "${a_inner_loop[@]:1}" )
for s_fqdn2 in ${a_inner_loop[@]} do echo "- ${s_fqdn2}"
done
done