阶乘式循环遍历数组

阶乘式循环遍历数组

我有一个 bash 主机数组。

a_hosts=( "host1.q.d.n",
  "host2.q.d.n",
  "host3.q.d.n",
  ...
  "hostN.q.d.n"
)

我需要将每个主机上的特定文件与所有其他主机上的相同文件进行比较。

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.

我的想法基于这个解决方案,但当我尝试循环时,我总是把自己逼到墙角loopN-1 代替循环通过loopN.我几乎认为我必须复制该数组,并保持两个数组同步。但是,这又是另一个循环。

有没有人想出一个优雅的解决方案来处理这种循环操作?


编辑1:

我正在尝试这个。

# 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

编辑2:

确认!抱歉,我的错误过于简化了我的示例。如果我的主机列表确实是host1, host2, ..., hostN,那么这将是一个简单得多的问题。遗憾的是,我在多个域中需要处理多种 FQDN,因此没有任何简单的解决方案host$i能够发挥作用。好消息是:我想我已经找到了有用的东西。

答案1

使用元素的索引进行循环,然后在嵌套循环中使用该索引偏移数组:

#! /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[@]}- 数组中所有元素的索引
  • ${a_hosts[@]:i+1}- 从偏移量开始的数组i+1(对数组下标进行算术扩展)。

示例输出(不带逗号):

% 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

答案2

Muru 和 dafydd 已经为您提供了优雅的方法。这是暴力破解的方法:

#! /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

答案3

这在 Bash 4 中有效。最好的部分是它完全不知道源数组的内容。

设置源数组。

a_fqdns=( "h1.q.d.n" "h5.r.d.n" "i21.s.d.n" ... )

对于外循环,弹出最后一个元素,因为该元素对应的内部循环将为空。

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}

从内循环中弹出第一个元素(索引 0)。这将导致外循环每次迭代时内循环缩小一个元素(索引 0)。请注意与的每次迭代a_outer_loop[i]具有相同的值。a_inner_loop[0]a_outer_loop

而且,unset 'a_inner_loop[0]'不会在这里工作。unset不会弹出索引 0,它只是将索引 0 的值更改为空字符串。

  a_inner_loop=( "${a_inner_loop[@]:1}" )
  for s_fqdn2 in ${a_inner_loop[@]}
  do
    echo "- ${s_fqdn2}"
  done
done

相关内容