배열에 대한 계승 루프

배열에 대한 계승 루프

나는 일련의 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

관련 정보