Edu*_*eia 3 grep text-processing pcre toml
我有一个以下格式的 TOML 文件(类别可以有任何名称,顺序编号只是一个例子,不能保证):
[CATEGORY_1]
A=1
B=2
[CATEGORY_2]
C=3
D=4
E=5
...
[CATEGORY_N]
Z=26
Run Code Online (Sandbox Code Playgroud)
我想要实现的是检索给定类别中的文本。
所以,如果我指定,比方说,[CATEGORY_1]
我希望它给我输出:
A=1
B=2
Run Code Online (Sandbox Code Playgroud)
我尝试使用标志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
Run Code Online (Sandbox Code Playgroud)
除非我删除^
了表达式开头的 ,否则它不起作用。但是,如果我这样做,它会将松散的括号错误解释为一个类别。
有没有办法正确地做到这一点?如果没有grep
,则使用其他工具,例如sed
或awk
。
您可以考虑使用tomlq
,一个TOML包装器jq
从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
Run Code Online (Sandbox Code Playgroud)
然后
$ tomlq -t '.CATEGORY_1' file.toml
A = 1
B = 2
Run Code Online (Sandbox Code Playgroud)
...并使用命令行上给出的部分名称:
$ cat file.toml
[CATEGORY_1]
A=1
B=2
[CATEGORY_2]
C=3
D=4
E=5
[CATEGORY_N]
Z=26
Run Code Online (Sandbox Code Playgroud)
输出为 TOML 格式。你想要制表符分隔的输出:
$ tomlq -t '.CATEGORY_1' file.toml
A = 1
B = 2
Run Code Online (Sandbox Code Playgroud)
使用@csv
代替@tsv
获取 CSV 输出。
由于您最初询问了 grep 解决方案,因此pcregrep
:
$ pcregrep -Mo '(?s)\[CATEGORY_1\]\n\K.*?(?=\n+\[)' file.toml
A=1
B=2
Run Code Online (Sandbox Code Playgroud)
where (?s)
make .
match\n
以便.*?
跨多行匹配。您可以使用以下-z
标志在 PCRE 模式下使用 GNU grep 伪造它:
$ grep -Pzo '(?s)\[CATEGORY_1\]\n\K.*?\n(?=\n+\[)' file.toml
A=1
B=2
Run Code Online (Sandbox Code Playgroud)
由于它具有固定的长度,你可以更换\[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
Run Code Online (Sandbox Code Playgroud)
awk
variable catname
。p
设置为 1 ,它将打印当前行(请参阅此处了解其工作原理)。[
与两端]
),我们设置标志为0,但如果行的类别名称完全匹配,我们设置了标志1(中的感觉:我们设置p
到检查$0
当前行是否等于存储在catname
) 中的字符串的结果。这样,从类别标题开始到下一个类别标题的所有内容都将被打印。
如果要省略类别标题,可以更改
{p=($0==catname)}
Run Code Online (Sandbox Code Playgroud)
到
{p=($0==catname); next}
Run Code Online (Sandbox Code Playgroud)
这将在设置标志后立即跳过处理到下一行,从而绕过条件打印指令。
如果另外您想排除空行,p
请将程序末尾的“看似杂散”更改为p&&NF
,这仅在标志p
非零且至少有一个“字段”(即非空白)时才为真文本)在当前行。
如果我理解正确,您可以使用以下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
Run Code Online (Sandbox Code Playgroud)