중첩 루프가있는 쉘 스크립트가 있는데 "exit"가 실제로 스크립트를 종료하지 않고 현재 루프 만 종료한다는 것을 알았습니다. 특정 오류 조건에서 스크립트를 완전히 종료하는 다른 방법이 있습니까?
허용되는 오류가 있고 너무 많은 재 작성이 필요하기 때문에 "set -e"를 사용하고 싶지 않습니다.
지금은 kill을 사용하여 프로세스를 수동으로 종료하고 있지만 더 좋은 방법이 있어야합니다.
중첩 루프가있는 쉘 스크립트가 있는데 "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에 의해 제공되었습니다. 좋은 하루 보내세요 :-)
bash --version
명령 행에 입력하십시오 .
이전 대답은 사용 제안 [[ $? != 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
for((i=0;i<3;i++));do echo A;for((j=0;j<2;j++));do echo B;break 2;done;done
bash -c 'for x in y z; do exit; done; echo "This never gets printed"'
.