중첩 루프 및 배열

중첩 루프 및 배열

Bash에서 중첩 for 루프를 사용하는 방법을 모르겠습니다. 다음 코드를 중첩된 for 루프로 어떻게 바꿀 수 있나요?

~/
❯ cat sequential.sh
a=(1 2)
b=(3 4)
c=(5 6)

for e in "${a[@]}"
do
    echo $e
done

for e in "${b[@]}"
do
    echo $e
done

for e in "${c[@]}"
do
    echo $e
done

✦ ~/
❯ bash sequential.sh
1
2
3
4
5
6

답변1

루프와 관련된 "중첩"이란 일반적으로 하나의 루프를 다른 루프 안에 넣어서 내부 루프의 각 반복 집합이 외부 루프의 각 반복에 대해 실행되도록 하는 것을 의미합니다.

for letter in a b c; do
    for digit in 1 2 3; do
        printf 'Letter = %s\tDigit = %s\n' "$letter" "$digit"
    done
done

...산출

Letter = a      Digit = 1
Letter = a      Digit = 2
Letter = a      Digit = 3
Letter = b      Digit = 1
Letter = b      Digit = 2
Letter = b      Digit = 3
Letter = c      Digit = 1
Letter = c      Digit = 2
Letter = c      Digit = 3

그러나 귀하의 질문에 따르면 여전히 동일한 출력을 원한다고 가정하면 중첩을 수행하고 싶지 않은 것 같습니다. 대신에 당신이 원하는결합하다세 개의 개별 루프를 하나의 루프로 결합합니다.

이는 루프 헤더에 배열 확장을 하나씩 추가하여 반복할 더 큰 문자열 세트를 생성함으로써 수행됩니다.

a=(1 2)
b=(3 4)
c=(5 6)

for item in "${a[@]}" "${b[@]}" "${c[@]}"
do
    printf 'item is "%s"\n' "$item"
done

이는 세 개의 작은 배열에서 별도의 요소 배열을 만들고 더 큰 배열을 반복하는 것과 동일한 효과를 갖습니다.

a=(1 2)
b=(3 4)
c=(5 6)

combined=( "${a[@]}" "${b[@]}" "${c[@]}" )

# the above has the effect of setting the combined array as
# combined=( 1 2 3 4 5 6 )

for item in "${combined[@]}"; do
    printf 'item is "%s"\n' "$item"
done

또는 더 짧게 위치 인수 목록을 사용합니다.

a=(1 2)
b=(3 4)
c=(5 6)

set -- "${a[@]}" "${b[@]}" "${c[@]}"

for item do
    printf 'item is "%s"\n' "$item"
done

이는 중첩이 아니라 배열 요소의 세 가지 개별 세트를 더 큰 세트로 결합하는 것입니다.


printf우리가 원하는 것이 최소한의 코드로 세 배열의 요소를 출력하는 것이라면 모든 매개변수가 출력될 때까지 형식 문자열이 모든 매개변수에 순차적으로 적용된다는 사실을 사용할 수 있습니다 .

a=(1 2)
b=(3 4)
c=(5 6)

printf 'item is "%s"\n' "${a[@]}" "${b[@]}" "${c[@]}"

또 다른 방법은 좀 어색하지만하다중첩 루프의 경우 실제 배열을 반복하고 각 배열을 차례로 처리하는 것입니다. bash쉘 에서는 루프를 통해 이 작업을 수행할 수 있습니다.이름이름 참조 변수가 있는 배열:

a=(1 2)
b=(3 4)
c=(5 6)

for arrayname in a b c; do
    declare -n array="$arrayname"
    for item in "${array[@]}"; do
        printf 'item is "%s" (from original array "%s")\n' "$item" "$arrayname"
    done
done

여기서 우리는 declare -n변수가 array현재 이름을 갖고 있는 모든 변수처럼 동작해야 한다고 종종 말합니다. arrayname그런 다음 array이를 배열인 것처럼 사용합니다. 이는 확장된 값이 $arrayname배열의 이름이기 때문에 작동합니다.

이것은 다소 특이한 프로그래밍 방식 bash이지만 작동합니다. 또한 별도의 배열 처리 함수를 도입하여 코드를 더 복잡하게 만들 수 있습니다(이 특별한 경우에는 이 코드를 작성하는 적절한 방법이 아닙니다. 단일 printf명령문을 사용하고 루프를 전혀 사용하지 않는 것이 더 좋습니다. 위에 표시됨) :

a=(1 2)
b=(3 4)
c=(5 6)

process_array () {
    local -n array="$1"
    for item in "${array[@]}"; do
        printf 'item is "%s" (from original array "%s")\n' "$item" "$arrayname"
    done
}

for arrayname in a b c; do
    process_array "$arrayname"
done

이는 "함수에 배열 전달"입니다(실제로 변수를 참조하는 로컬 이름이 있는 함수에서 배열 이름으로 사용되는 변수 이름 전달).

여기에는 몇 가지 제한 사항이 있습니다. 예를 들어, process_array이름 참조 변수를 사용하여 다른 함수를 호출할 수 없습니다 array. 당신은 또한 볼 수 있습니다bash 쉘 함수에는 순환 이름 참조가 있지만 ksh에는 없습니다.

답변2

✦ ~/
❯ cat nested.sh
a=(1 2)
b=(3 4)
c=(5 6)

for arr in "${a[@]}" "${b[@]}" "${c[@]}"
do
    for e in "${arr[@]}"
    do
        echo $e
    done
done

✦ ~/
❯ bash nested.sh
1
2
3
4
5
6

✦ ~/

관련 정보