如何使用 sed 或 awk 在模式开始/模式结束中插入数据?



我有一个 yaml 文件文件,其中包含ssl_ruleN其中 N 是 1 到 100 之间的数字。 我想添加每个规则local:cipher_suites.cipher_suites_ruleN,所以我需要在for中匹配每个规则。 尝试使用 sed,但问题显然是它也与规则 10 和规则 1 匹配。这样,它最终 rule2 也包含来自 rule20 的数据。

和输入文件:

ssl_rule.ssl_rule1: {action: block, dst_networks: 'local:rule_networks_fragment.RoutedNetGrpSelection1',
dst_services: 'local:rule_ports_fragment.PortSelectionSSL', dst_zones: 'local:rule_zones_fragment.ZoneSelectionRouted',
name: ssl_rule1, rid: 1, src_networks: 'local:rule_networks_fragment.RoutedNetGrpSelection1',
src_zones: 'local:rule_zones_fragment.ZoneSelectionRouted'}
ssl_rule.ssl_rule10: {action: block, dst_networks: 'local:rule_networks_fragment.RoutedNetGrpSelection10',
dst_services: 'local:rule_ports_fragment.PortSelectionSSL', dst_zones: 'local:rule_zones_fragment.ZoneSelectionRouted',
name: ssl_rule10, rid: 10, src_networks: 'local:rule_networks_fragment.RoutedNetGrpSelection10',
src_zones: 'local:rule_zones_fragment.ZoneSelectionRouted'}
ssl_rule.ssl_rule11: {action: block, dst_networks: 'local:rule_networks_fragment.RoutedNetGrpSelection11',
dst_services: 'local:rule_ports_fragment.PortSelectionSSL', dst_zones: 'local:rule_zones_fragment.ZoneSelectionRouted',
name: ssl_rule11, rid: 11, src_networks: 'local:rule_networks_fragment.RoutedNetGrpSelection11',
src_zones: 'local:rule_zones_fragment.ZoneSelectionRouted'}
ssl_rule.ssl_rule12: {action: block_with_reset, dst_networks: 'local:rule_networks_fragment.RoutedNetGrpSelection12',
dst_services: 'local:rule_ports_fragment.PortSelectionSSL', dst_zones: 'local:rule_zones_fragment.ZoneSelectionRouted',
name: ssl_rule12, rid: 12, src_networks: 'local:rule_networks_fragment.RoutedNetGrpSelection12',
src_zones: 'local:rule_zones_fragment.ZoneSelectionRouted'}
ssl_rule.ssl_rule25:
action: decrypt_resign
decryption_certs: ['local:internal_ca_certificate.Internal_Cert_4096']
dst_networks: local:rule_networks_fragment.RoutedNetGrpSelection25
dst_services: local:rule_ports_fragment.PortSelectionSSL
dst_zones: local:rule_zones_fragment.ZoneSelectionRouted
name: ssl_rule25
rid: 25
src_networks: local:rule_networks_fragment.RoutedNetGrpSelection25
src_zones: local:rule_zones_fragment.ZoneSelectionRouted

我尝试过:

for i in `seq 1 53`;do 
sed  "/ssl_rule.ssl_rule${i}[:] /,/action:/{s/action:/cipher_suites: 'local:cipher_suites.cipher_suites_rule$i', action:/g;}" -i  cucu.yaml
done

但它以某种方式混淆了规则,规则 10 包含规则 1 等等。请注意,我使用了/start/,/end/模式,因为技术因为有时规则跨越几行,我也想匹配它们(示例 rule25 )

预期输出(每个规则内部要包含local:cipher_suites.cipher_suites_ruleNNruleN相对应)

ssl_rule.ssl_rule1: {local:cipher_suites.cipher_suites_rule1, action: block, dst_networks: 'local:rule_networks_fragment.RoutedNetGrpSelection1',
dst_services: 'local:rule_ports_fragment.PortSelectionSSL', dst_zones: 'local:rule_zones_fragment.ZoneSelectionRouted',
name: ssl_rule1, rid: 1, src_networks: 'local:rule_networks_fragment.RoutedNetGrpSelection1',
src_zones: 'local:rule_zones_fragment.ZoneSelectionRouted'}

如注释中所述,您显然不希望sed从行匹配ssl_rule修改到下一个行匹配action:

此外,多次遍历文件并在每次传递时执行一次替换是非常低效和不优雅的。在大多数情况下,您应该告诉sed要对整个文件执行的操作。

为了在其中一个匹配规则之后立即匹配下一个action:行,我会切换到 Awk,这使得这种事情变得非常容易。

awk '/^ssl_rule.ssl_rule/ { r = 0 + substr($1, 18); n = (r >= 1 && r <= 53) }
n && /action:/ { sub(/action:/, "cipher_suites: 47local:cipher_suites.cipher_suites_rule" r "47, action:/"); n = 0} 1'  cucu.yaml >cucu.tmp &&
mv cucu.tmp cucu.yaml

回到一个sed答案,只是为了将一些松散的末端联系在一起。

正则表达式([1-9]|[1-4][0-9]|5[0-3)匹配数字 1 到 53。 括号还可以方便地捕获匹配的数字,因此我们可以在替换字符串中使用1来引用它。

sed -i '/ssl_rule.ssl_rule([1-9]|[1-4][0-9]|5[0-3): /s/action:/cipher_suites: '"'"'local:cipher_suites.cipher_suites_rule1'"'"', action:/' -i  cucu.yaml

我在这个脚本周围切换到单引号,然后要求文字单引号用一个稍微奇怪的'"'"'序列表示,该序列关闭当前的单引号表达式,添加一个文字单引号(用双引号引号引号以将其从外壳中转义)并打开一个新的单引号表达式,所有这些都彼此相邻。

不需要反斜杠转义冒号,但应该对点进行转义以使其字面匹配(未转义的点匹配任何字符)。

最新更新