仅为特定部分打印配置文件中的行
Print lines from config files for specific section only
我有很多部分的配置文件。我需要从特定部分收集所有行。该部分可能会在一个文件中出现多次。
例如:
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]+:
与 ports: 匹配,deсide 排除 ports:。
^\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:
但是,我不知道所有可能的部分名称。
我需要一个通用的解决方案。
根据您的数据格式,类似这样的方法应该可行
$ awk '/^[^ ]/{s=[=10=]} /:/{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
您的输入是 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
这可能适合您 (GNU sed):
sed '/:$/h;//d;G;/ports:$/P;d' file
将每个部分名称存储在保留 space 中,然后删除该行。对于每隔一行,附加最近的部分名称,如果恰好是 ports:
,则仅打印当前行。
我有很多部分的配置文件。我需要从特定部分收集所有行。该部分可能会在一个文件中出现多次。 例如:
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]+:
与 ports: 匹配,deсide 排除 ports:。
^\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:
但是,我不知道所有可能的部分名称。 我需要一个通用的解决方案。
根据您的数据格式,类似这样的方法应该可行
$ awk '/^[^ ]/{s=[=10=]} /:/{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
您的输入是 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
这可能适合您 (GNU sed):
sed '/:$/h;//d;G;/ports:$/P;d' file
将每个部分名称存储在保留 space 中,然后删除该行。对于每隔一行,附加最近的部分名称,如果恰好是 ports:
,则仅打印当前行。