特定のカテゴリタイトルから次のカテゴリタイトルまで、テキストファイルからテキストを抽出します。

特定のカテゴリタイトルから次のカテゴリタイトルまで、テキストファイルからテキストを抽出します。

次の形式のTOMLファイルがあります(カテゴリには任意の名前を持つことができ、シリアル番号は単なる例であり、保証されません)。

[CATEGORY_1]
A=1
B=2

[CATEGORY_2]
C=3
D=4

E=5

...

[CATEGORY_N]
Z=26

私が達成したいのは、与えられたカテゴリ内でテキストを検索することです。

したがって、私が指定した場合は、[CATEGORY_1]出力を提供したいと思います。

A=1
B=2

私はフラグを使用して改行文字をヌルバイト文字として解釈し、次の正規表現を使用してgrepこれを実行しようとしました。z

(^\[.*])             # Match the category 
  ((.*\n*)+?         # Match the category content in a non-greedy way
    (?=\[|$))        # Lookahead to the start of other category or end of line

^最初に式を削除しないと機能しません。しかし、これは緩い括弧のペアをカテゴリとして誤って解釈します。

これを正しく実行する方法はありますか?そうでない場合やgrep他のツールを使用してください。sedawk

答え1

tomlqTOMLjqラッパーの使用を検討することができます。yqプロジェクトname、単に構文を使用してjqカテゴリの内容を検索できます。.name

前任者。与えられた:

$ cat file.toml 
[CATEGORY_1]
A=1
B=2

[CATEGORY_2]
C=3
D=4

E=5


[CATEGORY_N]
Z=26

それから

$ tomlq -t '.CATEGORY_1' file.toml
A = 1
B = 2

...コマンドラインに指定された部分名を使用します。

$ tomlq -t --arg section 'CATEGORY_1' '.[$section]' file.toml
A = 1
B = 2

出力はTOML形式です。タブ区切りの出力が必要ですか?

$ tomlq -r --arg section 'CATEGORY_1' '.[$section] | to_entries[] | [ .key, .value ] | @tsv' file.toml
A       1
B       2

@csv代わりにCSV出力を得るために使用してください@tsv


元のgrepソリューションを要求したので、次のようになりますpcregrep

$ pcregrep -Mo '(?s)\[CATEGORY_1\]\n\K.*?(?=\n+\[)' file.toml
A=1
B=2

ここでは、複数の行を一致させるために(?s)使用されます。あなた.\n.*?できる-z次のフラグを使用して、PCREモードでGNU grepを使用して偽にします。

$ grep -Pzo '(?s)\[CATEGORY_1\]\n\K.*?\n(?=\n+\[)' file.toml
A=1                                                                                                                                                                                          
B=2

長さが固定されているので、対称性を好む場合は、正面図と一致するように\[CATEGORY_1\]\n\K背面図に置き換えることができます。(?<=\[CATEGORY_1\]\n)(?=\n+\[)

答え2

pureよりもやや複雑sedですが、より微調整できます。

$ awk -v catname="[CATEGORY_1]" '/^\[.*\]$/{p=($0==catname)} p' input.toml
[CATEGORY_1]
A=1
B=2

  • コマンドラインから希望のカテゴリ名をawk変数として指定できますcatname
  • プログラム内でフラグがp1に設定されている場合は、現在の行を印刷します(参照:ここ仕組みについて)。
  • 「カテゴリ開始パターン」(行が始まり[終了])が見つかった場合はフラグを0に設定しますが、行がカテゴリ名と正確に一致する場合はフラグを1に設定します(ある意味、Theを設定します)。現在行が)に格納されている文字列と同じであることをp確認した結果です。$0catname

これにより、カテゴリタイトルの先頭から次のカテゴリタイトルまですべての内容が印刷されます。

目標拡張

カテゴリのタイトルを省略したい場合は変更できます。

{p=($0==catname)}

到着

{p=($0==catname); next}

その後、条件付き印刷コマンドをバイパスし、フラグが設定されるとすぐに次の行にジャンプします。

また、空白行を除外するには、pプログラムの最後にある「見た目を失ったように見える」をに変更しますp&&NF。これは、フラグがpゼロではなく、1つ以上の「フィールド」(例:0以外)の場合にのみ正しいテキストです。空白))を現在の行に入力します。

答え3

私が正しく理解した場合は、次のコマンドを使用できますsed

# Choose the category until the next [ character
# and then delete any line starting with the [ character
$ sed -n '/^\[CATEGORY_2\]/,/^\[/p' file | sed '/^\[/d'
C=3
D=4

E=5

関連情報