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)を持つ最も右側のコマンドの終了状態になるようにします。あなたの場合、唯一のパイプはecho+jqパイプであり、echo失敗する可能性がないため、そのpipefailオプションは重複します。

errexit()シェルオプションを使用するset -eと、ゼロ以外の終了ステータスを返す最初のコマンドでシェルが終了します。〜しない限りこのコマンドは、コード内のものと同じAND-ORリストの一部です。

!!! json parse error: 'xxxx'コード出力をトリガーする唯一の方法は、シェルが書き込めifない場合にゼロ以外の終了状態を返す複合コマンドを使用することです$file_path

個人的に、私はこれらの2つのシェルオプションが絶対に必要な状況でなければ避けたいと思います(私のシェルスクリプトではこれらの状況の1つを見たことがありません)。


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が発生したときにゼロ以外の終了状態が返されますが(通常のように)、最終式で空の結果が生成された場合、またはnull返されますfalse

答え2

なぜそのメッセージを見たいと思うのか、本当に理解できません。コマンドグループの終了コードをテストしています。これは、グループの最後のコマンドの終了コードをテストしていることを意味します。あなたの場合、最後のコマンドはiftrueifの場合は次のようになりますecho

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

これが最後のコマンド実行なのでそれ|| echo "!!! json parse error: 'xxxx'"はテスト中のオブジェクトであり、両方が実行されifechotrueを返すため、「catchブロック」を入力しません。

オプションのため、これを行う場合はpipefailパイプではないため、機能しません。

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

ただし、パイプの後ろに失敗することなく別のコマンドを追加すると、次のようになります。

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

これがスクリプトに入る内容です。

関連情報