我有许多部分的配置文件。我需要收集特定部分的所有行。该部分可能在一个文件中出现几次。 例如:
serviceA:
ports:
8080
1323
serviceB:
test:
MMMM
ports:
8081
3123
network:
ddddd
我阅读了https://www.shellhacks.com/sed-awk-print-lines-between-two-patterns/这篇文章并开始。
本节开头的模式很简单,它是/ports:/
,但是本节末尾的模式不是那么简单,可以是任何名称,例如[a-zA-Z]+:
我尝试在awk和sed中使用模式[a-zA-Z]+:
。
awk。它仅打印部分名称
awk '/ports:/,/[a-zA-Z]+:/' file
ports:
ports:
在sed中。它从第一个端口打印到文件结尾
sed -n '/ports:/,/[a-zA-Z]+:/p' file
ports:
8080
1323
serviceB:
test:
MMMM
ports:
8081
3123
network:
ddddd
我认为问题在于模式[a-zA-Z]+:
与port:匹配,并决定排除port:。
^\s*((?!ports)[a-zA-Z]+:)+
这种模式在在线正则表达式测试器中可以正常使用-https://regex101.com/
awk从第一个端口打印到文件结尾
awk '/ports:/,/^\s*((?!ports)[a-zA-Z]+:)+/' file
ports:
8080
1323
serviceB:
test:
MMMM
ports:
8081
3123
network:
ddddd
目前,我只发现一种情况
awk '/ports:/,/network:|serviceB:/'
ports:
8080
1323
serviceB:
ports:
8081
3123
network:
但是,我不知道各节的所有可能名称。 我需要一个通用的解决方案。
答案 0 :(得分:1)
这可能对您有用(GNU sed):
sed '/:$/h;//d;G;/ports:$/P;d' file
将每个节名称存储在保留空间中,然后删除该行。对于每隔一行,请附加最新的节名称,如果恰好是ports:
,则仅打印当前行。
答案 1 :(得分:0)
根据您的数据格式,类似的东西应该起作用
$ awk '/^[^ ]/{s=$0} /:/{p=0} /ports:/{print s; p=1} p' file
serviceA:
ports:
8080
1323
serviceB:
ports:
8081
3123
捕获服务名称,如果port:
与打印服务名称和部分匹配,请在下一个子部分或部分中重置打印标志p
。
如果不需要节名
$ awk '/:/{p=0} p; /ports:/{p=1}' file
8080
1323
8081
3123
答案 2 :(得分:0)
您的输入为YAML,最好使用YAML
解析器来解析此数据。
您可以使用此ruby
代码打印ports
,该代码位于所有顶部的第二级:
ruby -ryaml -e "data=YAML::load(STDIN.read); data.each{|n|puts n.last['ports']}" < file.yml
8080 1323
8081 3123