Text-Processing

從文本文件中提取從特定類別標題開始的文本到下一個類別標題

  • August 25, 2021

我有一個以下格式的 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

您可能會考慮使用來自yq 項目tomlq的 TOML 包裝器,它允許您簡單地使用語法來檢索類別的內容。jq``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代替@tsv來獲取 CSV 輸出。


由於您最初詢問了 grep 解決方案,因此pcregrep

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

where (?s)make .match\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+\[)

比 pure 稍微複雜一些sed,但可以進行更多微調:

$ awk -v catname="[CATEGORY_1]" '/^\[.*\]$/{p=($0==catname)} p' input.toml
[CATEGORY_1]
A=1
B=2
  • 您可以在命令行上將所需的類別名稱指定為awkvariable catname
  • p在程序內部,如果標誌設置為 1 ,它將列印目前行(請參閱此處了解其工作原理)。
  • 如果我們遇到“類別開始模式”(行以 開頭[和結尾]),我們將標誌設置為 0,但如果行與類別名稱完全匹配,我們將標誌設置為 1(在某種意義上:我們設置p為檢查$0目前行是否等於儲存在catname) 中的字元串的結果。

這樣,從類別標題到下一個類別標題的所有內容都將被列印。

延伸目標

如果要省略類別標題,可以更改

{p=($0==catname)}

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

這將在設置標誌後立即跳過處理到下一行,從而繞過條件列印指令。

如果您還想排除空行,p​​請將程序末尾的“看似雜亂無章”更改為p&&NF,這僅在標誌p非零且至少有一個“欄位”(即非空白文本)在目前行。

引用自:https://unix.stackexchange.com/questions/662484