![루프에서 벗어날 때 0이 아닌 종료 코드가 트리거됩니다.](https://linux55.com/image/104146/%EB%A3%A8%ED%94%84%EC%97%90%EC%84%9C%20%EB%B2%97%EC%96%B4%EB%82%A0%20%EB%95%8C%200%EC%9D%B4%20%EC%95%84%EB%8B%8C%20%EC%A2%85%EB%A3%8C%20%EC%BD%94%EB%93%9C%EA%B0%80%20%ED%8A%B8%EB%A6%AC%EA%B1%B0%EB%90%A9%EB%8B%88%EB%8B%A4..png)
일련의 작업을 실행하고 그 중 하나라도 실패하면 중지하고 싶었기 때문에 다음과 같이 썼습니다.
for task in [TASKS]; do
process "$task" || break
commit "$task"
done
이것은 잘 작동하지만 (예:지정됨) 일찍 중단하더라도 루프의 종료 상태는 0입니다. 이상적으로 break
-ing은 실패를 전달할 수 있습니다.
0
반환이 문서화된 동작이라는 것을 알고 있지만 break
상대적으로 깔끔한 해결 방법이 있는지 궁금합니다. 내가 상상할 수 있는 최선의 방법은 이를 함수로 감싸서 didBreak
변수를 설정하고 이를 (함수의) 종료 상태로 사용하는 것입니다. 작동하지만 지나치게 복잡하다고 느껴집니다.
답변1
이는 많은 쉘에서 사용될 수 있습니다 ! break
(pdksh 기반 쉘 및 sh
FreeBSD 쉘 제외(통과 설계) 내 테스트에서):
$ zsh -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ bash -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ ksh88 -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ ksh93 -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ dash -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ yash -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ bosh -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ pdksh -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
0
$ mksh -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
0
$ posh -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
0
errexit
어느 쪽에서도 실행 되지 않습니다 .
그것은austin-group(POSIX 뒤에 있는 기관) 메일링 리스트에 대해 토론하세요.작년. ( bosh
FreeBSD sh
및 NetBSD 관리자 가 포함된) 논의는 sh
합의에 도달하기 전에 끝났지만 일반적인 견해는 POSIX가 !
명령의 종료 상태를 부정함으로써 문서화된 대로 이 동작을 요구했으며 break
이는 명령의 종료 상태를 부정하는 특별한 내장 명령이라는 것이었습니다. 0 종료 상태로 종료합니다.
그러나 예를 들어 동일한 추론을 적용하면 return
계산서에 맞는 껍질이 더 적다는 것을 알게 될 것입니다.
에서는 대신 익명 함수를 zsh
사용할 수 있습니다 .return
break
$ () for i in x y; do echo $i; return 1; done
x
$ echo $?
1
답변2
당신은 다음과 같은 것을 할 수 있습니다
failed=false
for task in "${tasks[@]}"; do
if ! process "$task"; then
failed=true
break
fi
commit "$task"
done
if "$failed"; then
echo "Failed something" >&2
fi
답변3
내가 상상하는 해결책은 다음과 같다.
run_til_failure() {
local didBreak=0
for task in [TASKS]; do
process "$task" || { didBreak=1; break; }
commit "$task"
done
local loopExit=$?
if (( loopExit )); then return $loopExit; fi
return $didBreak
}