Text-Processing
從文本文件中提取從特定類別標題開始的文本到下一個類別標題
我有一個以下格式的 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
,則使用其他工具,例如sed
或awk
。
您可能會考慮使用來自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
- 您可以在命令行上將所需的類別名稱指定為
awk
variablecatname
。p
在程序內部,如果標誌設置為 1 ,它將列印目前行(請參閱此處了解其工作原理)。- 如果我們遇到“類別開始模式”(行以 開頭
[
和結尾]
),我們將標誌設置為 0,但如果行與類別名稱完全匹配,我們將標誌設置為 1(在某種意義上:我們設置p
為檢查$0
目前行是否等於儲存在catname
) 中的字元串的結果。這樣,從類別標題到下一個類別標題的所有內容都將被列印。
延伸目標
如果要省略類別標題,可以更改
{p=($0==catname)}
至
{p=($0==catname); next}
這將在設置標誌後立即跳過處理到下一行,從而繞過條件列印指令。
如果您還想排除空行,
p
請將程序末尾的“看似雜亂無章”更改為p&&NF
,這僅在標誌p
非零且至少有一個“欄位”(即非空白文本)在目前行。