첫 번째 실행

첫 번째 실행

다음 스크립트가 있습니다 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)과 같은 출력이 제공됩니다.func1func2

$ 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

시간을 투자하면 이 모든 것을 완전히 이해할 수 있습니다. 더 많은 로깅이 필요하므로 실행하십시오.세게 때리다인수를 사용하면 -xbash가 명령을 실행하기 전에 앞에 +.

첫 번째 실행

$ 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출력 f22하위 셸의 종료 코드를 반환합니다.
  • 문제는 할당과 달리 종료 코드 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.

관련 정보