다음 스크립트가 있습니다 sandbox.sh
.
#!/bin/bash
set -eu -o pipefail -E
function func1() {
echo "FUNC1"
exit 1
}
function func2() {
local ret
ret=$(func1)
echo $ret
echo "(func2)This line shouldn't be reached:'${?}'" >&2
}
var=$(func1) # The Line
echo "main:This line shouldn't be reached:'${var}':'${?}'" >&2
(GNU bash, 버전 4.4.20(1)-릴리스(x86_64-pc-linux-gnu))
예상대로 실행이 중지됩니다.
$ bash -eu sandbox.sh
$
그러나 "The Line"을 수정하여 를 호출하면 다음 var=$(func2)
과 같은 출력이 제공됩니다.func1
func2
$ bash sandbox.sh
(func2)This line shouldn't be reached:'0'
main:This line shouldn't be reached:'FUNC1':'0'
$
나에게 명령 대체는 함수 내부에 배치될 때 다르게 동작하는 것처럼 보이지만 bash가 왜 이런 식으로 설계되었는지 이해가 되지 않습니다. 또한 한 함수의 출력이 다른 함수에서 사용될 수도 있으며 이러한 차이점은 혼란스럽습니다.
참고: 아래와 같이 func2를 다시 작성하면
function func2() {
func1
}
스크립트는 The Line에서 중지됩니다. 그러나 나는 프로그래머들이 func1의 출력을 조작하고 싶어하는 경우가 많다고 생각합니다.
답변1
시간을 투자하면 이 모든 것을 완전히 이해할 수 있습니다. 더 많은 로깅이 필요하므로 실행하십시오.세게 때리다인수를 사용하면 -x
bash가 명령을 실행하기 전에 앞에 +
.
첫 번째 실행
$ bash -x sandbox.sh; echo $?
+ set -eu -o pipefail -E
++ func1
++ echo FUNC1
++ exit 1
+ var=FUNC1
1
-e
설명하다이것명령이 0이 아닌 값을 반환하면 쉘은 즉시 종료됩니다. 그러나func1
서브쉘에서 실행(사용)하는 것이 중요합니다$(
)
. 위의 추적은 두 개의+
s를 접두사( )로 사용하여++
이 사실을 보여줍니다 .- 서브쉘은 stdout에 출력을 인쇄
FUNC1
하고 반환 코드 1로 종료됩니다.- 참고:
-e
이 하위 셸 내에서 닫습니다. 서브쉘이 종료된 이유는 명령 때문이었습니다exit
.-e
작성된func1
방식으로는 실제로 알 수 없습니다.
- 참고:
- 첫 번째 셸로 돌아가서
FUNC1
변수에 할당합니다.변하기 쉬운. 그러나 이 할당 명령의 종료 코드는마지막 명령 대체의 종료 코드입니다..불다이 실패(즉, 0이 아닌 종료 코드)를 확인하고 종료하세요.
참조 매뉴얼간단한 명령 확장부분:
확장 중 하나에 명령 대체가 포함된 경우 해당 명령의 종료 상태는 마지막으로 실행된 명령 대체의 종료 상태입니다.
두 번째 실행
첫 번째 실행과 정확히 동일한 설명입니다. 우리는 이것이 -e
서브쉘 내에서는 작동하지 않는다는 점을 다시 한 번 강조합니다. 그러나 이번에는 한 가지 큰 차이점이 있습니다. 즉, 무슨 일이 일어나고 있는지 훨씬 더 명확하게 알 수 있다는 것입니다.
- 종료 코드는
func2
마지막 명령의 종료 코드입니다. - 그것은
echo
항상 효과가 있습니다. func2
항상 성공- 임무는 항상 성공합니다.
-e
효과가 없습니다.
shopt -s inherit_errexit
?
이것은 서브쉘에서 열립니다 -e
. 그러나 이것은 어려운 동반자입니다. 명령이 실패할 때 어설션할 것이라는 보장은 없습니다.
생각해 보세요:
set -e
shopt -s inherit_errexit
f() { echo a; (exit 22); echo b; }
echo "f says [$(f)] $?"
echo byee
echo
이번에는 명령 대체가 할당의 일부가 아닌 값의 일부이므로 다음과 같은 결과를 얻습니다.
+ set -e
+ shopt -s inherit_errexit
++ f
++ echo a
++ exit 22
+ echo 'f says [a] 22'
f says [a] 22
+ echo byee
byee
- 서브쉘은 종료 코드 22와 함께 실패한 명령을 확인합니다. 명령이
-e
유효하므로 쉘은 코드 22(echo b
실행 없이)로 종료됩니다. - 첫 번째 셸,
echo
얻은a
출력f
및22
하위 셸의 종료 코드를 반환합니다. - 문제는 할당과 달리 종료 코드
echo
가 0이라는 것입니다.
버전
$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.