Loop de estilo fatorial através de uma matriz
Eu tenho uma matriz bash de hosts.
a_hosts=( "host1.q.d.n",
"host2.q.d.n",
"host3.q.d.n",
...
"hostN.q.d.n"
)
Preciso comparar um arquivo específico em cada host com o mesmo arquivo em todos os outros hosts.
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.
Tenho ideias baseadas nesta solução , mas continuo me encurralando quando tento passar por loopN-1 dentro de um loop loopN. Quase acho que preciso duplicar o array e manter os dois arrays sincronizados. Mas, isso é mais um loop.
Alguém encontrou uma solução elegante para esse tipo de manipulação de loop?
EDIT 1:
Estou experimentando isso.
# 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:
Ack! Desculpe, minha culpa por simplificar demais meu exemplo. Se a minha lista de anfitriões foram realmente host1, host2, ..., hostN, isso seria um problema muito mais simples. Infelizmente, tenho várias variedades de FQDNs para lidar, em vários domínios, portanto, nenhuma solução é tão fácil quanto host$ifunciona. A boa notícia é: acho que tenho algo que funcionará.
Respostas
Faça um loop usando o índice dos elementos e, em seguida, desloque a matriz usando esse índice no loop aninhado:
#! /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[@]}- os índices de todos os elementos da matriz${a_hosts[@]:i+1}- a matriz começando do deslocamentoi+1(a expansão aritmética é realizada no subscrito da matriz).
Saída com o exemplo (sem vírgulas):
% 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 e dafydd já deram a você as abordagens elegantes. Aqui está o de força bruta:
#! /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
Isso funciona no Bash 4. A melhor parte é que é totalmente independente do conteúdo do array de origem.
Defina sua matriz de origem.
a_fqdns=( "h1.q.d.n" "h5.r.d.n" "i21.s.d.n" ... )
Para o loop externo, pop o elemento final , pois o loop interno correspondente estaria vazio para aquele elemento.
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}
Retire o primeiro elemento (índice 0) do loop interno. Isso resultará na redução do loop interno em um elemento (índice 0) para cada iteração do loop externo. Observe que a_outer_loop[i]tem o mesmo valor a_inner_loop[0]de cada iteração de a_outer_loop.
Além disso, unset 'a_inner_loop[0]'não funcionará aqui. unsetnão exibe o índice 0, apenas altera o valor do índice 0 para uma string vazia.
a_inner_loop=( "${a_inner_loop[@]:1}" )
for s_fqdn2 in ${a_inner_loop[@]} do echo "- ${s_fqdn2}"
done
done