bash "catch block"은 잘못된 하위 쉘을 포착하지 않습니다.

bash "catch block"은 잘못된 하위 쉘을 포착하지 않습니다.

그래서 나는 이것을 가지고 있습니다 :

  (
        set -eo pipefail;
         {
          set -eo pipefail;
        file_path="$(echo "$i" | jq -r '.file_path')"

         if [[ -n "$file_path" ]]; then
              echo "$i" > "$file_path";
          fi
        } || {
           # never seems to reach here
           echo "!!! json parse error: 'xxxx'";
        }
     )

내 터미널에서 다음과 같은 것을 원합니다.

!!! json parse error: 'xxxx'

jq그런데 터미널에서 계속 이런 오류가 발생합니다.

parse error: Invalid numeric literal at line 2, column 0

나에게 일반적으로 작동하는 "catch 블록"이 여기서 작동하지 않는 이유를 잘 모르겠습니다.

답변1

의 쉘 pipefail옵션은 bash파이프의 종료 상태가 0이 아닌 종료 상태(또는 모든 명령이 성공적으로 종료된 경우 0)를 갖는 가장 오른쪽 명령의 종료 상태가 되도록 합니다. 귀하의 경우 가지고 있는 유일한 파이프는 echo+ jq파이프이며 echo실패할 가능성이 없으므로 해당 pipefail옵션이 중복됩니다.

errexit( ) 셸 옵션을 사용 set -e하면 0이 아닌 종료 상태를 반환하는 첫 번째 명령에서 셸이 종료됩니다.~하지 않는 한이 명령은 코드에 있는 것과 같은 AND-OR 목록의 일부입니다.

!!! json parse error: 'xxxx'코드 출력을 트리거 하는 유일한 방법은 if쉘이 쓸 수 없는 경우 0이 아닌 종료 상태를 반환하는 복합 명령을 사용하는 것입니다 $file_path.

개인적으로 나는 이 두 가지 쉘 옵션이 절대적으로 필요한 상황이 아니라면 피하고 싶습니다(내 쉘 스크립트에서는 이러한 상황 중 하나를 본 적이 없습니다).


jq구문 분석에서 null이 아닌 값이 생성되면 JSON 문서를 파일(의 출력에서 ​​제공)에 쓰고 구문 분석에 실패하면 오류 메시지를 출력하려는 ​​것 같습니다.

아마도 구문 분석이 잘 되었는지 확인하는 가장 쉬운 방법은 명령문 jq에서 직접 종료 상태를 사용하는 것입니다.if

여기서는 오류 출력을 추가로 캡처하여 jq자체 오류 보고에 사용합니다.

if filepath=$( jq -r '.file_path' <<<"$json_document" 2>&1 )
then
    # Parsing went ok.
    if [ -n "$filepath" ]; then
        # "$filepath" is non-empty.
        printf '%s\n' "$json_document" >"$filepath"
    fi
else
    # Parsing failed.
    printf 'ERROR: "%s"\n' "$filepath" >&2
fi

jq하지만 솔직히 말해서 전혀 개입하지 않고 자체적으로 오류 보고를 수행하도록 하여 코드를 단순화했습니다.

if filepath=$( jq -r '.file_path' <<<"$json_document" ) && [ -n "$filepath" ]
then
    # Parsing went ok, and "$filepath" is non-empty.
    printf '%s\n' "$json_document" >"$filepath"
fi

또는 jq값이 비어 있다고 가정하면 테스트가 제거됩니다 -n.

if filepath=$( jq -r -e '.file_path' <<<"$json_document" )
then
    # Parsing went ok, and "$filepath" is non-empty (and not null or false).
    printf '%s\n' "$json_document" >"$filepath"
fi

의 경우 -e오류 jq발생 시 0이 아닌 종료 상태가 반환되지만(보통과 같이) 최종 표현식에서 빈 결과가 생성되면 , null또는 도 반환됩니다 false.

답변2

왜 그 메시지를 보길 기대하는지 정말 이해가 안 돼요. 명령 그룹의 종료 코드를 테스트하고 있습니다. 이는 그룹의 마지막 명령의 종료 코드를 테스트하고 있음을 의미합니다. 귀하의 경우 마지막 명령은 if또는 iftrue인 경우 다음과 같습니다 echo.

  if [[ -n "$file_path" ]]; then
    echo is n
  fi

이것이 마지막 명령 실행이므로저것|| echo "!!! json parse error: 'xxxx'"은 테스트 중인 개체 이며 , 둘 다 실행 if되고 echotrue를 반환하므로 "catch 블록"을 입력하지 않습니다.

옵션 때문에 이 작업을 수행하려는 경우 pipefail파이프가 아니기 때문에 작동하지 않습니다.

$ { false | true; } || echo FAILED
$ set -o pipefail 
$ { false | true; } || echo FAILED
FAILED

그러나 이제 파이프 뒤에 실패 없이 다른 명령을 추가하면 다음과 같습니다.

 $ { false | true; true;} || echo FAILED
 $ 

이것이 스크립트에 들어가는 내용입니다.

관련 정보