sed或perl正则表达式替换文件中的部分

时间:2017-01-24 22:07:04

标签: 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.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
            ...

3 个答案:

答案 0 :(得分:3)

鉴于您显示的确切文字

perl -0777 -ne 's/flannel:[^}]+}//; print' file.txt

通过观察,文本中没有}可以删除。因此,它使用否定字符类[^}]匹配}以外的任何字符。因此,对于+,它与第一个}匹配。见in perlretutin perlrecharclass。 请调整其他文字。

或使用

perl -0777 -ne 's/flannel:.+?(?=etcd2:)+//s; print' file.txt

使用正向前瞻 (?=...)。它是零宽度断言,这意味着它匹配最多该模式并且不消耗它。它只是“看起来”(断言)它就在那里。见in perlretut。在这种情况下,我们还需要修饰符 /s,这使得.也匹配换行符。

-0[oct/hex]开关设置输入记录分隔符 $/-00将其设置为空行,从而按段落读取,这不是您需要的。 -0由[{1}}字符输入的null拆分,它不太可能存在于文件中,因此它通常“可以”立即读取整个文件。但是,一个正确的方式来篡改文件是指定大于-0400的任何内容,-0777是习惯用法。见Command line switches in perlrun

此处您可以使用-p代替-n,然后删除print,因为-p会打印$_

答案 1 :(得分:1)

在命令行规范-00ne中,您要求“段落”模式(两个零)。如果我正确理解你的问题,我想你想要篡改文件。这将使用一个零。

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

注意标记msm在'line'的开头处进行^匹配,而不是在'string'开头匹配的默认行为。 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

答案 2 :(得分:1)

它是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;