SSH를 통한 for 루프에 두 개의 배열을 중첩하면 연결된 사용자가 원치 않게 순열됩니다.

SSH를 통한 for 루프에 두 개의 배열을 중첩하면 연결된 사용자가 원치 않게 순열됩니다.

3개 노드의 일부 파일을 업데이트하려고 하는데각 연결을 특정 사용자 경로에 바인딩. 나는 이것에 익숙하지 않기 때문에 for loop루트로 연결하는 데 사용한 확장을 다음으로 확장했습니다.nested for loop 2개의 서로 다른 배열이 있습니다..

다음 스크립트물론 모든 연결에서 3개의 사용자 경로를 모두 사용해 보세요.. 나는 또한 arraywith만을 사용하여 시도한 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

배열 배열을 제한하는 방법이 있습니까?첫 번째 어레이 연결은 첫 번째 어레이 사용자 이름에만 해당됩니다.,등?

그렇지 않으면 무엇이 옳은가각 연결을 해당 사용자 경로에만 일치시키는 루프 구성이 있습니까?

답변1

응, 반복해색인그들의 것이 아닌 배열의 것가치. 그런데 두 배열은 인덱스를 공유하므로 반복자 변수가 하나만 필요합니다( $i아래).

bash배열은 0부터 시작하고 "${#arrayname[@]}"-를 사용하여 요소 수를 얻을 수 있으므로 0부터 그보다 작은 1까지 반복해야 합니다. 세 개의 요소를 포함하는 배열은 인덱스 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

관련 정보