通过 ssh 嵌套 for 循环中的两个数组会导致不需要的连接用户排列

通过 ssh 嵌套 for 循环中的两个数组会导致不需要的连接用户排列

我正在尝试更新 3 个节点上的一些文件,我想要将每个连接与特定的用户路径结合起来。因为我对此很陌生,所以我for loop将我用来作为 root 连接的扩展扩展为nested for loop 有2个不同的数组

以下脚本当然尝试在每个连接上使用所有 3 个用户路径。我还尝试使用arrayonly with ips,然后每个用户都尝试连接到所有 3 个节点。

#!/bin/bash
EXTENSIONS='/home/bi/.local/share/gnome-shell/extensions'
NODE_SRVS=(
'[email protected]'
'[email protected]'
'[email protected]'
)
NODE_USERS=(
'mf'
'lf'
'qf'
)

echo -e "sync my extensions to my nodes \c"; read
for i in ${NODE_SRVS[@]}; do
  for u in ${NODE_USERS[@]}; do
    rsync -rt --delete --info=progress2,stats2 \
    -e ssh -tt \
    $EXTENSIONS/ \
    $i:/home/$u/.local/share/gnome-shell/extensions/
  done
done

有没有办法限制数组排列第一个数组连接仅对应于第一个数组用户名, ETC?

否则什么是正确的循环构造以将每个连接仅匹配到相应的用户路径?

答案1

是的,迭代指数数组的,而不是它们的价值观。顺便说一句,这两个数组共享索引,因此您只需要一个迭代器变量($i如下)。

bash数组从零开始,你可以使用"${#arrayname[@]}"- 获得元素的数量,所以你需要从零迭代到比它少的一。包含三个元素的数组将具有索引 0、1 和 2 - 假设创建数组时索引中没有间隙。我所说的“间隙”是指数字索引“缺失”(要么从未插入到数组中,要么在插入后一段时间被删除) - 例如,数组可能具有索引 1、3 和 5。缺少 2 和 4。

例如

i=0
while [ "$i" -lt "${#NODE_SRVS[@]}" ] ; do

   # setting $h and $u isn't strictly necessary but makes the code
   # easier to read, at little performance cost.
   h="${NODE_SRVS[$i]}"
   u="${NODE_USERS[$i]}"

   rsync -rt --delete --info=progress2,stats2 \
    -e ssh -tt \
    "$EXTENSIONS/" \
    "$h:/home/$u/.local/share/gnome-shell/extensions/

   let i+=1
done

您还可以用来"${!arrayname[@]}"获取所有索引的列表 - 仅列出存在的索引,忽略任何间隙。您可以使用以下方法迭代它for

for i in "${!NODE_SRVS[@]}" ; do 
  h=....
  u=...
  rsync ...
done

这对于索引数组很有用(因为可能存在间隙),但对于关联数组特别有用,这让我想到了下一个替代方案:使用关联数组(也称为“哈希”),例如,其中用户名是键(索引)和主机名/IP 地址是值(在像这样的简单情况下,将 IP 地址作为键、将用户名作为值也同样有效)。

declare -A NODES
NODES=([mf]=192.168.122.60)
NODES+=([lf]=192.168.122.92)
NODES+=([qf]=192.168.122.93)

EXTENSIONS="something"

for u in "${!NODES[@]}"; do 
  rsync -rt --delete --info=progress2,stats2 \
    -e ssh -tt \
    "$EXTENSIONS/" \
    "$u@${NODES[$u]}:/home/$u/.local/share/gnome-shell/extensions/"
done

echo行开头带有 的示例输出rsync

rsync -rt --delete --info=progress2,stats2 -e ssh -tt something/ [email protected]:/home/qf/.local/share/gnome-shell/extensions/
rsync -rt --delete --info=progress2,stats2 -e ssh -tt something/ [email protected]:/home/lf/.local/share/gnome-shell/extensions/
rsync -rt --delete --info=progress2,stats2 -e ssh -tt something/ [email protected]:/home/mf/.local/share/gnome-shell/extensions/

但请注意,bash 中的关联数组本质上是无序的 - 这意味着您将以有效的随机顺序迭代键。有时这很重要,有时则不重要。当无关紧要的时候,使用关联数组会很方便。当确实重要时,请使用两个索引数组,如上面第一个示例所示。

当您想要哈希的便利性但需要按照创建的顺序处理数组时,请使用哈希,但也使用索引数组,并将哈希的键作为数组的值。迭代索引数组以按照插入顺序获取哈希的键名称。例如

...

ORDER=(mf lf qf)

for u in "${ORDER[@]}"; do
  rsync -rt --delete --info=progress2,stats2 \
    -e ssh -tt \
    "$EXTENSIONS/" \
    "$u@${NODES[$u]}:/home/$u/.local/share/gnome-shell/extensions/"  
done

答案2

要迭代两个数组的配对元素而不是数组中元素的整体组合,请循环遍历一个数组并在每次迭代中从另一个数组中取出下一个元素。

如果第二个列表保留在位置参数列表中,那么这会变得更容易(就语法而言),我们可以使用它shift来删除元素:

#!/bin/bash

list1=( element1 element2 element3 )
list2=( thing1   thing2   thing3   )

# Assign the second list to
# the list of positional parameters:
set -- "${list2[@]}"

# Loop over the first list and pull out
# the next element of the second list
# in each iteration, to pair up the elements:
for element in "${list1[@]}"; do
    printf 'Pair: %s %s\n' "$element" "$1"
    shift
done

输出:

Pair: element1 thing1
Pair: element2 thing2
Pair: element3 thing3

将此应用到您的具体示例:

#!/bin/bash

node_servers=(
    '192.168.122.60'
    '192.168.122.92'
    '192.168.122.93'
)
node_users=(
    'mf'
    'lf'
    'qf'
)

extension_path=.local/share/gnome-shell/extensions

set -- "${node_users[@]}"

for server in "${node_servers[@]}"; do
    rsync -ai --delete ~bi/"$extension_path"/ "$1@$server:$extension_path"
    shift
done

但是,由于您的原始服务器列表已经包含用户名,因此我们不需要第二个列表:

#!/bin/bash

node_servers=(
    '[email protected]'
    '[email protected]'
    '[email protected]'
)

extension_path=.local/share/gnome-shell/extensions

for server in "${node_servers[@]}"; do
    rsync -ai --delete ~bi/"$extension_path"/ "$server:$extension_path"
done

上面的两个代码片段都假设当前目录将是我们正在连接的用户的主目录。

答案3

考虑到我感谢的所有建议,我更容易应用的解决方案是使用数组索引,如下所示:

#!/bin/bash
EXTENSIONS='/home/bi/.local/share/gnome-shell/extensions'
IPS=(
'192.168.122.60'
'192.168.122.92'
'192.168.122.93'
)
USERS=(
'mf'
'lf'
'qf'
)

echo -e "sync my extensions to my nodes \c"; read
for i in ${!IPS[*]}; do
  rsync -rt --delete --info=progress2,stats2 \
  -e ssh -tt \
  $EXTENSIONS/ \
  ${USERS[$i]}@${IPS[$i]}:/home/${USERS[$i]}/.local/share/gnome-shell/extensions/
done

相关内容