_errexit 상속이 작동하지 않는 경우는 언제인가요?

_errexit 상속이 작동하지 않는 경우는 언제인가요?
#!/usr/bin/env bash
set -e
shopt -s inherit_errexit
a=$(cat no-such-file)
echo survived
$ /tmp/a.sh
cat: no-such-file: No such file or directory
#!/usr/bin/env bash
set -e
shopt -s inherit_errexit
echo -n $(cat no-such-file)
echo survived
$ /tmp/a.sh
cat: no-such-file: No such file or directory
survived
#!/usr/bin/env bash
set -e
shopt -s inherit_errexit
f() { :; }
f $(cat no-such-file)
echo survived
$ /tmp/a.sh
cat: no-such-file: No such file or directory
survived

다른 경우도 있나요? 아니면 일부 일반화?

답변1

TL,DR: 이 기능을 활용하려면 set -e명령 대체 결과를 변수에 직접 할당하세요(선택적으로 주변에 추가 문자열을 추가). 여러 명령 대체를 함께 결합하거나 명령 매개변수에 명령 대체를 사용하지 마십시오.

문제는 inherit_errexit작동하는 것이 아닙니다. 문제는 set -e(이것은 bash에만 국한된 것이 아닙니다. 다른 sh와 유사한 쉘에도 동일한 문제가 있습니다) 제한 사항입니다.

데모: 두 번째 예제의 변형을 실행합니다.

$ cat b2.sh 
#!/usr/bin/env bash
set -e
shopt -s inherit_errexit
echo -n $(cat no-such-file; echo >&2 after cat)
echo survived
$ ./b2.sh 
cat: no-such-file: No such file or directory
survived

echo >&2 after cat실행이 없다는 점에 유의하세요 . 닫히면 이런 일이 발생합니다 inherit_errexit.

문제는 set -e오류가 발생한 경우 간단한 경우에만 실행이 중지된다는 점입니다. 명령 대체가 실패 상태를 반환하는 경우 대체를 포함하는 단순 명령의 실행이 중지되지 않습니다. 기껏해야 간단한 명령의 반환 상태를 설정하여 스크립트 실행을 중지할 수 있습니다. "간단한 명령"은 할당, 리디렉션, 선택적 실행 가능 명령 이름 및 인수로 구성됩니다. 리디렉션이 실패하면 반환 상태는 1입니다. 그렇지 않고 명령 이름이 있는 경우 단순 명령의 반환 상태는 실행 가능한 명령의 반환 상태입니다. 그렇지 않으면 반환 상태는 마지막 명령 대체의 반환 상태이거나, 없는 경우 0입니다. 다음은 간단한 명령의 몇 가지 예입니다.

  • true </no/such/file→ 리디렉션 실패로 인해 상태 1
  • false </dev/null→ 상태 1부터false
  • a=b→ 실패할 수 있는 구성 요소가 없으므로 상태 0
  • a=$(exit 0) b=$(exit 1) c=$(exit 2)→ 마지막 명령 대체 상태 2
  • a=$(exit 2) b=$(exit 1) c=$(exit 0)→ 마지막 명령 교체 후 상태 0
  • true $(exit 0) $(exit 1) $(exit 2)→ 상태 0부터true

다시 말하지만, 모든 경우에 set -e명령 상태가 0이 아닌 경우에만 스크립트가 중지됩니다. 포함된 명령의 상태는 직접적인 관련이 없습니다.

따라서 두 번째 스크립트에서는 명령 대체에서 어떤 일이 발생하더라도 echo -n $(…)상태는 0입니다 echo( echo쓸 수 없는 경우 제외). 따라서 스크립트가 set -e활성화되어 있어도 여기서 멈추지 않습니다. 마찬가지로 세 번째 스크립트에서는 f $(…)상태가 0 입니다 f.

관련 정보