私は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-content
YAML文書から最上位セクションを削除するには、次のコマンドを使用しますdel()
。
質問のサンプル文書をそのまま考慮すると、次のYAML文書が端末に書き込まれます。
/text-content:
post:
operationId: createStaticText
summary: Process text events
description: Process text events
parameters: []
requestBody: null
保存するには、新しいファイルにリダイレクトするか、その--in-place
オプションを使用してその場所で編集します(もちろん、まずオプションなしでテストした後)。
yq
jq
式を使用してjq
YAMLファイルを処理できるようにする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
値です。これらはkey
valueからvalue
適切なバーに戻すことはできないため、empty
valueに変更して完全に消えました。正直なところ、私はこのことの内部動作について完全にはわかりません。
これにより
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;