다음 스크립트가 있다고 가정해 보겠습니다 sandbox.sh
.
(이것은 다음과 유사하게 보일 것입니다.-e가 설정된 경우에도 함수 내의 명령 대체는 실패 시 스크립트를 중지하지 않습니다., 하지만 조금 다르다고 생각합니다)
"The Line"에서는 출력을 위치 인수로 전달하려고 합니다 func2
.func1
#!/bin/bash
set -eu -o pipefail -E
shopt -s inherit_errexit
function func1() {
local arg="${1}"
echo "(func1)This line shouldn't be reached:arg='${arg}': '${?}'" >&2
}
function func2() {
echo "value from func2"
exit 1
}
var="$(func1 "$(func2)")" # The Line
echo "main:This line shouldn't be reached:var='${var}':'${?}'" >&2
프로그래머가 기존 함수를 간결하게 재사용하여 데이터를 구조화하려는 경우가 가능한 상황이라고 생각합니다.
그러나 이렇게 하면 다음과 같은 출력이 생성됩니다.
$ bash sandbox.sh
(func1)This line shouldn't be reached:arg='value from func2': '0'
main:This line shouldn't be reached:var='':'0'
$
나는 이 동작을 호출 서브쉘이 서브쉘의 동작을 상속받지 func2
않는다는 의미로 해석합니다 . 따라서 설정되지 않은 값을 매개변수로 사용합니다.errexit
func1
func1
"The Line"을 다음과 같이 수정하여 작동시키려고 했습니다.
# A.
var="$(set -e; func1 "$(set -e; func2)")" # The Line
또는
# B.
var="$(func1 "$(func2 || exit 1)" || exit 1)" # The Line
그러나 아직 운이 없습니다. 사실 A.나 B. 모두 이 행동을 교정하지 않았다는 사실이 혼란스럽습니다. 이에 대한 모범 사례는 무엇입니까? 아니면 처음부터 명령 대체를 중첩하려고 하면 안 되나요?
답변1
지금까지의 답변(삭제된 것으로 보임)과 제가 수행한 실험을 바탕으로 이(중첩 명령 대체)는 기껏해야 "나쁜 습관" 또는 "매우 귀찮은" 것으로 간주될 수 있다고 생각하기 시작했습니다. .
내가 할 수 있는 최선은
#!/bin/bash
set -eu -o pipefail -E
shopt -s inherit_errexit
function func1() {
[[ $? == 0 ]]; return 1 # The boilerplate line
local arg="${1}"
echo "(func1)This line shouldn't be reached:arg='${arg}': '${?}'" >&2
}
function func2() {
echo "value from func2"
return 1
}
var="$(func1 "$(func2)")" # The line
echo "main:This line shouldn't be reached:var='${var}':'${?}'" >&2
그러면 예상되는 출력(비어 있음)과 0이 아닌(1) 종료 코드가 생성됩니다. 비결은 $?
그것이 0
함수 정의의 첫 번째 줄에 있는지 확인하는 것입니다. 이(상용구 라인)은 중첩된 명령 대체에서 재사용되는 각 함수 정의에 삽입되어야 합니다. 불안감 없이 "중첩 명령 대체" 구문을 사용하려면 새 함수를 생성할 때마다 상용구를 삽입하는 방법에 익숙해져야 합니다.
"보일러 라인"은 정말 무해합니까? 물론 그렇습니다. 그렇습니다. set -eu
어느 쪽이든 실패가 감지될 때마다 즉시 중단되기 때문입니다 . 하지만 저는 bash 프로그래밍에 능숙하지 않아서 잠재적인 함정을 놓쳤을 수도 있습니다. 좀 더 경험이 많은 사람들의 통찰력을 알고 싶습니다. 미리 감사드립니다.