YAMLファイルから特定のヘッダーの特定のサブセクションをすべて削除する方法は?

YAMLファイルから特定のヘッダーの特定のサブセクションをすべて削除する方法は?

私はbashシェルを使用しています。特定のテキストブロックを削除したいYAMLファイルがあります。

  /image-content:
    post:
      operationId: createEventPublic
      summary: Process events
      description: Process events
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Content'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Content'
  /text-content:
    post:
      operationId: createStaticText
      summary: Process text events
      description: Process text events
      parameters: []
      requestBody:
    ...

たとえば、パスに「イメージコンテンツ」を含むテキストブロックを削除したいとします。通常、この機能を使用して、そのテキストを含む1行を削除できます。

sed -i '/image-content/d' ./infile

しかし、次の行が2つのスペースと「/」(例: "/")で始まるまで、それ以降のすべての行をどのように変更するのかわかりません。上記の場合まですべてを削除したいと思います。

  /text-content:

編集する:これは有効なopenapi 3 swaggerではないかもしれませんが、それでもまだ有効なYAMLファイルだと思います。

openapi: 3.0.0
components:
  /static/image-content:
    post:
      type: hello
  /api/hello:
    post:
      type: hello
  /static/css-content:
    post:
      type: hello

最終的に「/static」で始まるブロックを削除したいと思います。したがって、最終文書は次のようになります。

openapi: 3.0.0
components:
  /api/hello:
    post:
      type: hello

答え1

yq -y 'del(."/image-content")' file.yml

これはyq以下で使用されます。https://kislyuk.github.io/yq//image-contentYAML文書から最上位セクションを削除するには、次のコマンドを使用しますdel()

質問のサンプル文書をそのまま考慮すると、次のYAML文書が端末に書き込まれます。

/text-content:
  post:
    operationId: createStaticText
    summary: Process text events
    description: Process text events
    parameters: []
    requestBody: null

保存するには、新しいファイルにリダイレクトするか、その--in-placeオプションを使用してその場所で編集します(もちろん、まずオプションなしでテストした後)。

yqjq式を使用してjqYAMLファイルを処理できるようにするJSONパーサーのラッパーです。


その文書が次のような場合部分の実際の構造を表示しない場合(2つのインデントスペースは2番目のレベルセクションが表示されることを意味します)、次のものを使用できます。

yq -y 'del(.[]."/image-content")' file.yml

この.[]."/image-content"表現は「/image-content最上層の下のすべて」を表します。

到着再帰的/image-contentセクションが文書のどこに表示されているかを検索して削除するには、次を使用します。

yq -y 'del(.. | ."/image-content"?)' file.yml

で使用された式はdel()ドキュメント構造を再帰的に検索し、名前付きセクションを含むすべてのセクションを..抽出します(これはXPathクエリの演算子に対応します)。その後、その内容を削除します。/image-content//


更新された質問を解決するには:

yq -y '.components |= with_entries(del(select(.key | startswith("/static/"))) // empty)' file.yml

componentsその後、サブセクションを取得し、一時的に個々のkey合計value値に変換し(マニュアルのドキュメントwith_entries()を参照jq)、キーが正しい文字列で始まるセクションを選択および削除してセクションを更新します/static/

bit // empty:del()演算の結果がnull値です。これらはkeyvalueからvalue適切なバーに戻すことはできないため、emptyvalueに変更して完全に消えました。正直なところ、私はこのことの内部動作について完全にはわかりません。

これにより

openapi: 3.0.0
components:
  /api/hello:
    post:
      type: hello

答え2

テスト用GNU sed

sed -n '
    /^\s*\/static/ {
        n
        :c
            /^[[:space:]]*\//! {
                n
                bc
            }
        }
    p
' data

したがって、2番目の質問は基本的に同じです。

sed -n '
    /^[[:space:]]\+\/image-content:$/ {
        n
        :c
            /^[[:space:]]\+\//! {
                n
                bc
            }
    }
    p
' data

最初の行は目的の段落を見つけ、新しい段落が見つかるまで各行を繰り返し削除します。もちろん、-i内部編集用にフラグを挿入することもできます。

答え3

一般的な解決策:一致する行とインデントされた行の両方を削除します。

特定の形式のファイルがある場合は、通常、その形式に合わせて特別に設計されたツールを使用するのが最善です。あなたの場合、行をインデントするためのスペースに基づいた単純な規則があるようですが、標準ツール用の簡単なスクリプトを提供するのはどうでしょうか。

sed -e 'H;x;/^\(  *\)\n\1/{s/\n.*//;x;d;}' -e 's/.*//;x;/\/image-content/{s/^\( *\).*/ \1/;x;d;}' file

すること:一致するパターンの行が見つかったら、予約済みスペースに空白の数だけ保存し、1つの空白を追加しながら削除します。次に、各行に対して少なくとも保持バッファと同じスペースで始まることを確認します。その場合、インデントの少ない行が保持スペースをリセットするまで、その行も削除されます。

詳細な説明

  • H;x現在の行をH以前のスペースに追加してスペースを交換するため、現在の行は予約済みスペースに保持され、パターンスペースでは以前の予約済みスペースに追加された行を確認できるようになりました。
  • /^\( *\)\n\1/予約済みスペースに少なくとも1つのスペースがあり、現在行に少なくとも予約済みバッファー分のスペースがあることを識別するパターン。つまり、次の行を削除する必要があり、この{}行はこの場合にのみ実行されることを意味します。
  • s/\n.*//改行文字で始まるすべての項目を消去するので、追加の行を削除し、以前に保持していたバッファにあった内容を復元します。xバッファを再び変更して前の状態に戻り、現在dのパターン空間を削除して新しいループを開始できるようになりました。
  • 残りのスクリプトは、行が削除されていない場合にのみ実行されます。s/.*//;xパターンスペースを消去してスペースを変更すると初期状態になります。現在行はパターンスペースにあり、予約済みスペースは空です。
  • 最後に、セクションのトリガーを削除する必要があります。\/image-contentすべてのトリガモードにすることができます。もちろん、\/staticそうかもしれません。すべてのインデントレベルで。したがって、以降のすべての操作はトリガラインでのみ実行されます。他のすべての行は単に印刷されます。
  • s/^\( *\).*/ \1/;xこの行のすべてのスペースを削除し、他のスペースを追加してから、将来の比較のために予約済みスペースに配置します(スクリプトの先頭で行った操作)。その後、d出力を防ぐために削除する必要があります。

答え4

  • コメントなし
sed '/^ *\/image-content:/{
:sub;
  $b eof;
  N;
/^\( *\)[^ ].*\n\1[^ ][^\n]*$/!b sub;
:eof;
  s/^\( *\)[^ ].*\n\(\1[^ ][^\n]*\)$/\2/;
  t loop;
  d;
:loop; n; b loop;
}' file;
  • コメントがあります
sed '/^ *\/image-content:/{
:sub;
  $b eof;  # end of file
  N;
/^\( *\)[^ ].*\n\1[^ ][^\n]*$/!b sub;  # leading-spaces==ending-spaces(\1). loop if not same level
:eof;
  # if join with the first-line of next block, only leave the joint-line.
  s/^\( *\)[^ ].*\n\(\1[^ ][^\n]*\)$/\2/;
  t loop;  # jump if s/././ is done
  d;  # no more lines after target block
:loop; n; b loop;  # b loop is to speed the process
}' file;

関連情報