중첩 루프가있는 쉘 스크립트 종료 있는데 “exit”가 실제로 스크립트를 종료하지

중첩 루프가있는 쉘 스크립트가 있는데 “exit”가 실제로 스크립트를 종료하지 않고 현재 루프 만 종료한다는 것을 알았습니다. 특정 오류 조건에서 스크립트를 완전히 종료하는 다른 방법이 있습니까?

허용되는 오류가 있고 너무 많은 재 작성이 필요하기 때문에 “set -e”를 사용하고 싶지 않습니다.

지금은 kill을 사용하여 프로세스를 수동으로 종료하고 있지만 더 좋은 방법이 있어야합니다.



답변

문제는 중첩 루프 자체가 아닙니다. 하나 이상의 내부 루프가 하위 쉘에서 실행 중입니다 .

이것은 작동합니다 :

#!/bin/bash

for i in $(seq 1 100); do
        echo i $i
        for j in $(seq 1 10) ; do
                echo j $j
                sleep 1
                [[ $j = 3 ]] && { echo "I've had enough!" 1>&2; exit 1; }
        done
        echo "After the j loop."
done
echo "After all the loops."

산출:

i 1
j 1
j 2
j 3
I've had enough!

이것은 당신이 설명한 문제를 나타냅니다 :

#!/bin/bash

for i in $(seq 1 100); do
        echo i $i
        cat /etc/passwd | while read line; do
                echo LINE $line
                sleep 1
                [[ "$line" = "daemon:x:2:2:daemon:/sbin:/sbin/nologin" ]] && { echo "I've had enough!" 1>&2; exit 1; }
        done
        echo "After the j loop."
done    
echo "After all the loops."

산출:

i 1
LINE root:x:0:0:root:/root:/bin/bash
LINE bin:x:1:1:bin:/bin:/sbin/nologin
LINE daemon:x:2:2:daemon:/sbin:/sbin/nologin
I've had enough!
After the j loop.
i 2
LINE root:x:0:0:root:/root:/bin/bash
LINE bin:x:1:1:bin:/bin:/sbin/nologin
LINE daemon:x:2:2:daemon:/sbin:/sbin/nologin
I've had enough!
After the j loop.
i 3
LINE root:x:0:0:root:/root:/bin/bash
(...etc...)

해결책은 다음과 같습니다. 서브 쉘에서 실행되는 내부 루프의 리턴 값을 테스트해야합니다.

#!/bin/bash

for i in $(seq 1 100); do
        echo i $i
        cat /etc/passwd | while read line; do
                echo LINE $line
                sleep 1
                [[ "$line" = "daemon:x:2:2:daemon:/sbin:/sbin/nologin" ]] && { echo "I've had enough!" 1>&2; exit 1; }
        done
        err=$?; [[ $err != 0 ]] && exit $err
        echo "After the j loop."
done
echo "After all the loops."

테스트에 유의하십시오. [[ $? != 0 ]] && exit $?

산출:

i 1
LINE root:x:0:0:root:/root:/bin/bash
LINE bin:x:1:1:bin:/bin:/sbin/nologin
LINE daemon:x:2:2:daemon:/sbin:/sbin/nologin
I've had enough!

편집 : 현재 사용중인 서브 쉘을 확인하려면 “응답”스크립트를 수정하여 현재 쉘의 프로세스 ID를 알려주십시오. 참고 : 이것은 bash 4에서만 작동합니다.

#!/bin/bash

for i in $(seq 1 100); do
        echo pid $BASHPID i $i
        cat /etc/passwd | while read line; do
                echo pid $BASHPID LINE $line
                sleep 1
                [[ "$line" = "daemon:x:2:2:daemon:/sbin:/sbin/nologin" ]] && { echo "I've had enough!" 1>&2; exit 1; }
        done
        err=$?; [[ $err != 0 ]] && echo pid $BASHPID && exit $err
        echo "After the j loop."
done
echo "After all the loops."

산출:

pid 31793 i 1
pid 31796 LINE root:x:0:0:root:/root:/bin/bash
pid 31796 LINE bin:x:1:1:bin:/bin:/sbin/nologin
pid 31796 LINE daemon:x:2:2:daemon:/sbin:/sbin/nologin
I've had enough!
pid 31793

변수 “i”와 “j”는 Fortran에 의해 제공되었습니다. 좋은 하루 보내세요 🙂


답변

이전 대답은 사용 제안 [[ $? != 0 ]] && exit $?그러나이하지 않습니다 확실히 예상대로 때문에, 작업을 [[ $? != 0 ]]테스트 재설정 $?, 제로로하는 수단을 백업하는 것이 비록 스크립트 것입니다 예상대로 조기 종료, 그것을거야 항상 코드 0으로 종료 (예상하지) . 또한 문자열 비교 테스트 -ne보다는 숫자 비교 테스트 를 사용하는 것이 좋습니다 !=. 따라서 IMHO의 더 나은 솔루션은 다음을 사용하는 것입니다.

err=$?; [[ $err -ne 0 ]] && exit $err

실제 종료 코드가 올바르게 설정되어 있는지 확인하십시오 .


답변

사용할 수 있습니다 break.

보낸 사람 help break:

Exit a FOR, WHILE or UNTIL loop.  If N is specified, break N enclosing loops.

따라서 세 개의 엔 클로징 루프를 종료하려면 (예 : 메인 루프 안에 두 개의 중첩 루프가있는 경우)이를 사용하여 모든 루프를 종료하십시오.

break 3


답변

exit 전체 쉘 또는 현재 하위 쉘을 종료합니다.

$ bash -c 'for i in 1 2 3; do for j in 4 5 6; do echo $i; exit 1; echo $j; done; done'
1
$ echo $?
1


답변