Regex sed或perl正则表达式替换文件中的节

Regex sed或perl正则表达式替换文件中的节,regex,perl,sed,Regex,Perl,Sed,我有一个文件,正在尝试使用正则表达式删除以下行: flannel: interface: $private_ipv4 etcd_endpoints: {{ .ETCDEndpoints }} 我尝试使用这个perl命令,它最终删除了#cloud config中的所有内容,直到--name:docker.service perl -i -00ne 'print unless /(flannel:).*([^ ]+).*([^ ]+).*}}/' file.txt file.tx

我有一个文件,正在尝试使用正则表达式删除以下行:

flannel:
    interface: $private_ipv4
    etcd_endpoints: {{ .ETCDEndpoints }}
我尝试使用这个perl命令,它最终删除了#cloud config中的所有内容,直到--name:docker.service

perl -i -00ne 'print unless /(flannel:).*([^ ]+).*([^ ]+).*}}/' file.txt
file.txt:

#cloud-config
coreos:
  update:
    reboot-strategy: "off"
  flannel:
    interface: $private_ipv4
    etcd_endpoints: {{ .ETCDEndpoints }}
  etcd2:
    name: controller
    advertise-client-urls: http://$private_ipv4:2379
    initial-advertise-peer-urls: http://$private_ipv4:2380
    listen-client-urls: http://0.0.0.0:2379
    listen-peer-urls: http://0.0.0.0:2380
    initial-cluster: controller=http://$private_ipv4:2380
  units:
    - name: etcd2.service
      command: start
      runtime: true

    - name: docker.service
      drop-ins:
        - name: 40-flannel.conf
          content: |
            [Unit]
            Requires=flanneld.service
            After=flanneld.service
            [Service]
            EnvironmentFile=/etc/kubernetes/cni/docker_opts_cni.env
            ...

在命令行spec
-00ne
中,要求使用“段落”模式(两个零)。如果我没弄错你的问题,我想你应该把文件弄脏。这将使用一个零

我使用了
perl-0777-pe的//^\s+flannel:.+?(?=^\s+etcd2)//ms的file.txt
来获得我认为您想要的:

注意标志
ms
m
使
^
在“行”开头匹配,而不是在“字符串”开头匹配的默认行为。
s
标志允许点(.)也匹配我给出的解决方案中需要的换行符

#cloud-config
coreos:
  update:
    reboot-strategy: "off"
  etcd2:
    name: controller
    advertise-client-urls: http://$private_ipv4:2379
    initial-advertise-peer-urls: http://$private_ipv4:2380
    listen-client-urls: http://0.0.0.0:2379
    listen-peer-urls: http://0.0.0.0:2380
    initial-cluster: controller=http://$private_ipv4:2380
  units:
    - name: etcd2.service
      command: start
      runtime: true

    - name: docker.service
      drop-ins:
        - name: 40-flannel.conf
          content: |
            [Unit]
            Requires=flanneld.service
            After=flanneld.service
            [Service]
            EnvironmentFile=/etc/kubernetes/cni/docker_opts_cni.env

在命令行spec
-00ne
中,要求使用“段落”模式(两个零)。如果我没弄错你的问题,我想你应该把文件弄脏。这将使用一个零

我使用了
perl-0777-pe的//^\s+flannel:.+?(?=^\s+etcd2)//ms的file.txt
来获得我认为您想要的:

注意标志
ms
m
使
^
在“行”开头匹配,而不是在“字符串”开头匹配的默认行为。
s
标志允许点(.)也匹配我给出的解决方案中需要的换行符

#cloud-config
coreos:
  update:
    reboot-strategy: "off"
  etcd2:
    name: controller
    advertise-client-urls: http://$private_ipv4:2379
    initial-advertise-peer-urls: http://$private_ipv4:2380
    listen-client-urls: http://0.0.0.0:2379
    listen-peer-urls: http://0.0.0.0:2380
    initial-cluster: controller=http://$private_ipv4:2380
  units:
    - name: etcd2.service
      command: start
      runtime: true

    - name: docker.service
      drop-ins:
        - name: 40-flannel.conf
          content: |
            [Unit]
            Requires=flanneld.service
            After=flanneld.service
            [Service]
            EnvironmentFile=/etc/kubernetes/cni/docker_opts_cni.env

给定您显示的确切文本

perl -0777 -ne 's/flannel:[^}]+}//; print' file.txt
这是通过观察到要删除的文本中没有
}
来实现的。因此,它使用求反字符类
[^}]
,该类匹配除
}
以外的任何字符。因此,对于
+
,它将所有内容匹配到第一个
}
。看看这个,然后。 请调整其他文本

或使用

perl -0777 -ne 's/flannel:.+?(?=etcd2:)+//s; print' file.txt
它使用正向前瞻
(?=…)
。它是一个零宽度断言,意味着它匹配该模式,并且不使用它。它只是“看起来”(断言)它就在那里。看到了。在这种情况下,我们还需要修饰符
/s
,它使
也与换行符匹配

-0[oct/hex]
开关设置输入记录分隔符
$/
-00
将其设置为空行,因此按段落阅读,这不是您需要的。
-0
通过
null
字符分割输入,该字符不太可能出现在文件中,因此通常一次读取整个文件“有效”。但是,正确地读取文件的方法是指定大于
-0400
的任何内容,而
-0777
是惯例。看


在这里,您可以使用
-p
而不是
-n
,然后删除
print
,因为
-p
会打印
$\uu
,只要您显示的是准确的文本

perl -0777 -ne 's/flannel:[^}]+}//; print' file.txt
这是通过观察到要删除的文本中没有
}
来实现的。因此,它使用求反字符类
[^}]
,该类匹配除
}
以外的任何字符。因此,对于
+
,它将所有内容匹配到第一个
}
。看看这个,然后。 请调整其他文本

或使用

perl -0777 -ne 's/flannel:.+?(?=etcd2:)+//s; print' file.txt
它使用正向前瞻
(?=…)
。它是一个零宽度断言,意味着它匹配该模式,并且不使用它。它只是“看起来”(断言)它就在那里。看到了。在这种情况下,我们还需要修饰符
/s
,它使
也与换行符匹配

-0[oct/hex]
开关设置输入记录分隔符
$/
-00
将其设置为空行,因此按段落阅读,这不是您需要的。
-0
通过
null
字符分割输入,该字符不太可能出现在文件中,因此通常一次读取整个文件“有效”。但是,正确地读取文件的方法是指定大于
-0400
的任何内容,而
-0777
是惯例。看


在这里,您可以使用
-p
而不是
-n
,然后删除
print
,因为
-p
打印
$。

是YAML,所以请使用YAML解析器

#!/usr/bin/env perl
use strict;
use warnings;

use YAML::XS;
use Data::Dumper;

# <> is the magic file handle, it reads files on command line or STDIN. 
# much like grep/sed/awk do.     
my $conf = Load ( do { local $/; <> } );
#print for debugging. 
print Dumper $conf;

#delete the key you don't want. 
delete $conf->{coreos}{flannel};

#print output to STDOUT. 
#You can hack this into in place editing if you
#want. 
print Dump $conf;
#/usr/bin/env perl
严格使用;
使用警告;
使用YAML::XS;
使用数据::转储程序;
#是神奇的文件句柄,它读取命令行或STDIN上的文件。
#很像grep/sed/awk。
my$conf=Load(do{local$/;});
#打印以进行调试。
打印转储程序$conf;
#删除不需要的密钥。
删除$conf->{coreos}{flannel};
#将输出打印到标准输出。
#如果您愿意,您可以将其破解到就地编辑中
#需要。
打印转储$conf;

这是YAML,所以请使用YAML解析器

#!/usr/bin/env perl
use strict;
use warnings;

use YAML::XS;
use Data::Dumper;

# <> is the magic file handle, it reads files on command line or STDIN. 
# much like grep/sed/awk do.     
my $conf = Load ( do { local $/; <> } );
#print for debugging. 
print Dumper $conf;

#delete the key you don't want. 
delete $conf->{coreos}{flannel};

#print output to STDOUT. 
#You can hack this into in place editing if you
#want. 
print Dump $conf;
#/usr/bin/env perl
严格使用;
使用警告;
使用YAML::XS;
使用数据::转储程序;
#是神奇的文件句柄,它读取命令行或STDIN上的文件。
#很像grep/sed/awk。
my$conf=Load(do{local$/;});
#打印以进行调试。
打印转储程序$conf;
#删除不需要的密钥。
删除$conf->{coreos}{flannel};
#将输出打印到标准输出。
#如果您愿意,您可以将其破解到就地编辑中
#需要。
打印转储$conf;

谢谢perl-0777-ne的/flannel:[^}]+}//;print'file.txt worked..刚从您的原始回答中丢失了一个额外的},但是正确的方法是指定大于-0400和-0777的任何内容,这是一个很好的解释。正如文档中所述。@ChrisCharley是的,我可能已经看过几次了:)随着时间的推移,我学会了欣赏文档(Perl)和标准等(其他语言)的准确性和权威性。大多数情况下,这是唯一的最终答案。(在Perl中,真正的终极版当然是源代码。)感谢Perl-0777-ne的/flannel:[^}]+}//;print'file.txt worked..刚从您的原始回答中丢失了一个额外的},但是正确的方法是指定大于-0400和-0777的任何内容,这是一个很好的解释。如文件所述。@chrischalley是的,我可能已经看过那一页好几次了