종료 상태가 0이 아닌 명령이 "&& 또는 || 목록"의 일부임에도 불구하고 ERR 신호를 보내는 이유는 무엇입니까?

종료 상태가 0이 아닌 명령이 "&& 또는 || 목록"의 일부임에도 불구하고 ERR 신호를 보내는 이유는 무엇입니까?

man bash사용하려면 다음 문서를 포함하세요 trap.

trap [-lp] [[arg] sigspec ...]
    The ERR trap is not executed if the failed command is part of the command list
    immediately following a while or until keyword, part of the test in an if statement,
    part of a && or || list, or if the command's return value is being inverted via !.
    These are the same conditions obeyed by the errexit option.

나는 이해"&& 또는 ||의 부분 목록"이는 명령이 이러한 제어 연산자가 포함된 목록의 일부인 경우 종료 상태가 0이 아닌 경우에도 마찬가지입니다.ERR 신호를 보내면 안 됩니다.(또는 사용되는 경우 스크립트를 종료합니다 set -o errexit).

그러나 여기에 모순되는 것으로 보이는 테스트 스크립트가 있습니다.

#!/usr/bin/env bash

_trap_err() {
    local status=$? sig=$1 line=$2;
    echo "Exit status ${status} on line ${line}: \`${BASH_COMMAND}\`";
}
trap '_trap_err ERR $LINENO' ERR;

function control_operators() {
    # The next line will send an ERR signal.
    [[ 1 -eq 2 ]] && echo Hello;
}

control_operators;

# The next line will not send an ERR signal.
[[ 1 -eq 2 ]] && echo Hello;

echo Done;

출력은 다음과 같습니다

❯ test.sh
Exit status 1 on line 14: `[[ 1 -eq 2 ]]`
Done

[[ 1 -eq 2 ]]&& 또는 ||의 일부로 "나열"되어 있기 때문입니다 .ERR 신호가 트리거되어서는 안 됩니다..

예상되는 출력은 다음과 같습니다.

❯ test.sh
Done

또한, 그냥 나열[[ 1 -eq 2 ]] && echo Hello ~에control_operators함수는 ERR 신호를 보내지만[[ 1 -eq 2 ]] && echo Hello 외부이 기능은 그렇지 않습니다.

이 스크립팅 환경에 설정된 옵션은 다음과 같습니다(출력 set -o | grep 'on$').

braceexpand     on
hashall         on
interactive-comments    on
xtrace          on

질문:

  1. 이 동작이 정상입니까, 아니면 목록에서 제어 연산자를 잘못 사용하고 있습니까(또는 문서를 잘못 해석하고 있습니까)?
  2. 명령이 조건식의 일부이고 실제로 오류 조건을 구성하지 않는 경우 ERR 트랩 트리거를 방지하는 가장 좋은 방법은 무엇입니까?
    • || true한 가지 옵션은 각 목록 끝에 추가된 제어 연산자를 사용하는 것입니다 .
    • if [[ 1 -eq 2 ]]; then echo Hello; fi또 다른 옵션은 대신 약어를 사용하는 것입니다 . 이는 (에 따르면 ) "if 문에 있는 테스트의 일부"이기 &&때문에 ERR 신호가 전송되지 않습니다 . man bash&& 또는 ||" . 목록" 아니요.
  3. [[ 1 -eq 2 ]]ERR 신호가 함수 내부에서만 전송되는 이유는 무엇입니까 ?

고쳐 쓰다:@Kusalananda의 첫 번째 대답은 위의 예에서 정확합니다(함수에 추가하면 ERR 신호가 return 0방지됩니다 ). control_operators그러나 다음은 "&& 또는 || 규칙이 있는 목록의 일부"를 위반하는 것으로 보이는 또 다른 예입니다.

#!/usr/bin/env bash
_trap_err() {
    local status=$? sig=$1 line=$2;
    echo "Exit status ${status} on line ${line}: \`${BASH_COMMAND}\`";
}
trap '_trap_err ERR $LINENO' ERR;
true && false;
echo Done;

이 스크립트의 출력은 다음과 같습니다.

❯ test.sh
Exit status 1 on line 7: `false`
Done

이 줄은 true && false명령이 false"&& 또는 || 목록의 일부"이기 때문에 ERR 신호를 보내서는 안 됩니다. 그렇다면 왜 이렇게 할까요?

업데이트 2:저는 bash 3.2를 사용하여 macOS에서 작업하고 있습니다. 이것이 바로 man bash위의 스니펫에서 언급되지 않은 이유 입니다."마지막 && 또는 ||를 제외한 명령".

답변1

ERR호출의 반환 상태가 0이 아니기 때문에 control_operators스크립트가 트랩을 트리거하고 있습니다 . 함수 테스트는 그렇지 않습니다.곧장함정을 발동시키세요.

트랩 출력은 함수가 호출된 줄이 될 줄 번호를 인쇄하여 이를 나타냅니다.

또한 트랩 출력은 0이 아닌 종료 상태가 어디서 나오는지 나타내며, 이는 함수 테스트 결과입니다. 테스트는 함수에서 마지막으로 실행되는 것이므로 함수의 종료 상태를 설정합니다.

함수 호출이 AND 또는 OR 목록의 일부가 아니므로 트랩이 트리거됩니다.


업데이트된 질문에 대해 ERR0이 아닌 종료 상태를 반환하는 명령이 다음과 같은 경우 트랩이 계속 호출된다는 사실을 잊어버렸습니다.마지막목록의 AND 또는 OR 명령입니다.

bash매뉴얼 에서 나는 다음을 강조합니다.

ERR실패한 명령이 while또는 until키워드 바로 뒤에 있는 명령 목록의 일부이거나 명령문의 테스트 부분이거나 if목록에서 실행된 명령의 일부인 경우 트랩은 실행되지 않습니다.&&||&&마지막 또는 다음 명령을 제외하고||, 마지막 명령을 제외한 파이프라인의 모든 명령 또는 역방향 명령의 반환 값을 사용하는 경우 !.

귀하의 예는 이며 AND 목록의 마지막 true && false이므로 트랩을 트리거합니다.falseERR

그것을 표현하는 또 다른 방법은 다음과 같습니다 ERR.종료 상태로 결정목록이나 파이프에 대해 0이 아닌 종료 상태를 반환합니다( !또는 이 명령과 함께 사용되는 경우 0).

관련 정보