AFAICT, continue
for 루프 내에서 다른 함수를 호출하면 errexit
의미가 손상됩니다. main()
함수에서 오류가 발생하면 다음 반복을 계속하고 싶습니다 build()
.
#! /usr/bin/env bash
export PS4='# ${BASH_SOURCE}:${LINENO}: ${FUNCNAME[0]}() - [${SHLVL},${BASH_SUBSHELL},$?] '
set -o xtrace
set -o errexit
build() {
local _foo=$1
if [ "${_foo}" -eq 1 ]; then
false
fi
printf "%s with foo=%s builds ok\\n" "${FUNCNAME[0]}" "${_foo}"
}
main() {
for i in 1 2 3; do
build $i || continue
done
}
main "$@"
그러나 루프 continue
내부에서는 for
코드가 발생합니다.계속하다대신, 함수 내부에서 build()
플래그의 효과를 제거하십시오 errexit
.
$ ./foo.sh
# ./foo.sh:5: () - [3,0,0] set -o errexit
# ./foo.sh:23: () - [3,0,0] main
# ./foo.sh:18: main() - [3,0,0] for i in 1 2 3
# ./foo.sh:19: main() - [3,0,0] build 1
# ./foo.sh:8: build() - [3,0,0] local _foo=1
# ./foo.sh:10: build() - [3,0,0] '[' 1 -eq 1 ']'
# ./foo.sh:11: build() - [3,0,0] false
# ./foo.sh:14: build() - [3,0,1] printf '%s with foo=%s builds ok\n' build 1
build with foo=1 builds ok
# ./foo.sh:18: main() - [3,0,0] for i in 1 2 3
# ./foo.sh:19: main() - [3,0,0] build 2
# ./foo.sh:8: build() - [3,0,0] local _foo=2
# ./foo.sh:10: build() - [3,0,0] '[' 2 -eq 1 ']'
# ./foo.sh:14: build() - [3,0,0] printf '%s with foo=%s builds ok\n' build 2
build with foo=2 builds ok
# ./foo.sh:18: main() - [3,0,0] for i in 1 2 3
# ./foo.sh:19: main() - [3,0,0] build 3
# ./foo.sh:8: build() - [3,0,0] local _foo=3
# ./foo.sh:10: build() - [3,0,0] '[' 3 -eq 1 ']'
# ./foo.sh:14: build() - [3,0,0] printf '%s with foo=%s builds ok\n' build 3
build with foo=3 builds ok
printf
이전 줄의 종료 코드가 있는 줄에서 볼 수 있듯이 false
이는 실제로 1
(앞 대괄호 안의 세 번째 숫자) 이므로 errexit
제자리에 없는 것처럼 실행됩니다.
# ./foo.sh:14: build() - [3,0,1] printf '%s with foo=%s builds ok\n' build 1
|| continue
삭제하면 쉘이 종료되어 i=1
subhshell errexit
/ 함수에 전달되는 것을 확인했습니다 .
어떤 도움이라도 대단히 감사하겠습니다.
버전
~ $ bash --version
GNU bash, version 5.0.3(1)-release (x86_64-pc-linux-gnu)
고쳐 쓰다
다음 질문에 대한 좋은 답변이 많이 있습니다왜이것은. 문제를 해결하는 방법에 관해서는 이 솔루션이 내가 원하는 작업을 수행하도록 스크립트를 얻는 가장 쉬운 방법이라는 것을 알았습니다. 스크립트를 다음으로 변경하세요 false
.
false || return $?
물론 단점은 함수가 호출하는 모든 명령에 대해 이 작업을 수행해야 한다는 것입니다. run()
전달된 명령을 실행하고 반환 코드를 확인한 후 그에 따라 스크립트를 실패시키는 래퍼를 사용하는 이전 방식 으로 돌아가야 할 수도 있습니다 . 나는 errexit
당신이 할 것으로 예상되는 일을 할 것 같아요 :-)
답변1
-e
이는 / -errexit
의 설명과 일치하는 것 같습니다.배쉬 문서:
실패한 명령이 while 또는 Until 키워드(if 문의 테스트 부분) 바로 뒤에 있는 명령 목록의 일부인 경우 쉘은 종료되지 않습니다.&& 또는 || 내에서 실행되는 명령의 일부 목록마지막 && 또는 || 뒤의 마지막 명령을 제외한 파이프라인의 모든 명령이나 명령의 반환 상태는 !로 반전됩니다.
[...]-e를 생략한 컨텍스트에서 복합 명령 또는 셸 함수가 실행되는 경우 -e가 설정되고 명령이 오류를 반환하더라도 복합 명령 또는 함수의 본문 내에서 실행되는 모든 명령은 -e 설정의 영향을 받지 않습니다. 상태.
이것은 이미이 계산기 문제,다음으로 연결이 이메일그리고 다음 텍스트가 함께 제공됩니다.
> My initial gripe about errexit (and its man page description) is that the
> following doesn't behave as a newbie would expect it to:
>
> set -e
> f() {
> false
> echo "NO!!"
> }
> f || { echo "f failed" >&2; exit 1; }
Indeed, the correct behavior mandated by POSIX (namely, that 'set -e' is
completely ignored for the duration of the entire body of f(), because f
was invoked in a context that ignores 'set -e') is not intuitive. But
it is standardized, so we have to live with it.
이것POSIX설명은 -e
다음과 같습니다.
-e
이 옵션이 켜져 있으면 쉘 오류의 결과에 나열된 이유로 인해 간단한 명령이 실패하거나 종료 상태 값 >0을 반환하고 while, Until 또는 if 키워드 뒤에 오는 복합 목록의 일부가 아닌 경우 , 그리고AND 또는 OR 목록의 일부가 아님, 앞에는 파이프가 없습니다. 예약어를 사용하면 쉘이 즉시 종료되어야 합니다.
답변2
~에서수동[강조 내]:
errexit
와 동일합니다
-e
.
-e
파이프라인 [...](단일 단순 명령 [...], 목록 [...] 또는 복합 명령 [...]으로 구성될 수 있음)이 0이 아닌 상태를 반환하는 경우 즉시 종료하십시오.실패한 명령이
&&
[...]의 일부이거나 목록에서 실행된 명령(||
마지막 또는 다음 명령 제외)인 경우 쉘은 종료되지 않습니다.&&
||
,[…][…]
[...] 쉘 함수가 무시된 컨텍스트에서 실행되는 경우 [
-e
...] 함수 본문 내에서 실행되는 모든 명령은 이 설정이 설정되고 명령이 실패 상태를 반환-e
하더라도 이 설정의 영향을 받지 않습니다.-e
.[…]
쉘 기능은 무시된 build $i || continue
build
컨텍스트에서 실행됩니다. 함수 본문 내에서 실행되는 명령이므로 설정의 영향을 받지 않으므로 실행을 방해하지도 않습니다.-e
false
-e
printf
제거 || continue
하고 호출하면 build $i
함수의 각 부분이 다음 -e
과 같은 컨텍스트에 놓이게 됩니다.아니요false
은 무시되므로 및 이후 로 인해 전체 코드가 false
도착하지 않고 종료됩니다 printf
.
이는 errexit
(무시하지 않을 경우) 전체 스크립트를 종료하는 전역 설정인 것 같습니다. 함수를 종료하도록 할 수는 없지만(또는 적어도 쉽게는 할 수 없음) 전체 스크립트를 종료할 수는 없습니다.