Bash 使用sed处理完整的文本部分

Bash 使用sed处理完整的文本部分,bash,ubuntu,sed,Bash,Ubuntu,Sed,我第一次尝试bash脚本,但我一直坚持使用sed来更改配置文件。我需要编辑的键非常通用,在整个文件中都会用到,所以我必须依靠一个部分来知道在哪里进行“触摸” 因此,如前所述,文件周围有多个部分,由[section name]声明,然后在它下面,有该部分的配置,由一个选项卡缩进。有像enabled,type等键,它们在整个文件中使用 因此,完整的部分如下所示: [backend] # enabled = no # data source = average

我第一次尝试bash脚本,但我一直坚持使用
sed
来更改配置文件。我需要编辑的键非常通用,在整个文件中都会用到,所以我必须依靠一个部分来知道在哪里进行“触摸”

因此,如前所述,文件周围有多个部分,由
[section name]
声明,然后在它下面,有该部分的配置,由一个选项卡缩进。有像
enabled
type
等键,它们在整个文件中使用

因此,完整的部分如下所示:

[backend]
        # enabled = no
        # data source = average
        # type = graphite
        # destination = localhost
        # prefix = netdata
        # hostname = localhost
        # update every = 10
        # buffer on failures = 10
        # timeout ms = 20000
所以我需要做的是:

  • 取消对整个部分的注释
  • enabled=no
    更改为
    enabled=yes
  • destination
    的值更改为带有端口的IP地址(
    192.168.99.38:2003
  • hostname
    的值更改为另一个主机名,可能是机器的主机名(
    $hostname
    ?)

  • 问题是,我根本不知道如何解决这个问题。我已经查找了sed多行处理,但我确实不知道如何仅匹配
    [backend]
    部分。这对我来说是非常新的。

    sed
    不是这类东西的理想工具,但它可以做到:

    /^\[.*]$/h
    {G;/\n\[backend\]$/{
      s/#//
      /enabled/s/no/yes/
      /destination/s/localhost/whatever/
      /hostname/s/localhost/something else/
      }
      s/\n\[.*\]$//
    }
    

    sed
    不是这类东西的理想工具,但它可以做到:

    /^\[.*]$/h
    {G;/\n\[backend\]$/{
      s/#//
      /enabled/s/no/yes/
      /destination/s/localhost/whatever/
      /hostname/s/localhost/something else/
      }
      s/\n\[.*\]$//
    }
    
    正如你评论我的那样:只有[后端]下的内容,没有其他内容

    您可能会对使用Perl这样做感兴趣,如果就评论我;我会删除和回答

    假设您拥有此文件:

    [no-backend]
            # enabled = no
            # data source = average
            # type = graphite
            # destination = localhost
            # prefix = netdata
            # hostname = localhost
            # update every = 10
            # buffer on failures = 10
            # timeout ms = 20000
    
    [backend]
            # enabled = no
            # data source = average
            # type = graphite
            # destination = localhost
            # prefix = netdata
            # hostname = localhost
            # update every = 10
            # buffer on failures = 10
            # timeout ms = 20000
    
    [no-backend]
            # enabled = no
            # data source = average
            # type = graphite
            # destination = localhost
            # prefix = netdata
            # hostname = localhost
            # update every = 10
            # buffer on failures = 10
            # timeout ms = 20000  
    
    这一行为您找到该部分:

    perl  -lne '$b=$.; $e=($b+10) if /\[backend\]/;print if $b++<$e' file
    
    or readable version
    perl -lne 'if( /\[backend\]/ ){ $b=$.; $e=( $b+10 ); }; if( $b++ < $e ){ print }' file
    
    perl -lpe 'if(/\[backend\]/){$b=$.;$e=($b+10);};if($b++<$e){ s/#//;s/no/yes/;s/(?<=destination = ).+$/192.168.99.38:2003/;s/(?<=hostname = ).+$/\$HOSTNAME/ }' file
    
    现在,您可以使用以下内容修改该部分,而不是打印:

    s/#//;s/no/yes/;s/(?<=destination = ).+$/192.168.99.38:2003/;s/(?<=hostname = ).+$/$HOSTNAME/
    
    最后,在检查输出是否一切正常后,您可以使用
    -i
    选项使用在位编辑功能,如:

    perl-i.bak-lne'…脚本的其余部分…'文件

    .bak仅用于获取旧文件的备份。(如:file.txt.bak)


    更新以获取您的评论

    正如你评论我的那样:只有[后端]下的内容,没有其他内容

    您可能会对使用Perl这样做感兴趣,如果就评论我;我会删除和回答

    假设您拥有此文件:

    [no-backend]
            # enabled = no
            # data source = average
            # type = graphite
            # destination = localhost
            # prefix = netdata
            # hostname = localhost
            # update every = 10
            # buffer on failures = 10
            # timeout ms = 20000
    
    [backend]
            # enabled = no
            # data source = average
            # type = graphite
            # destination = localhost
            # prefix = netdata
            # hostname = localhost
            # update every = 10
            # buffer on failures = 10
            # timeout ms = 20000
    
    [no-backend]
            # enabled = no
            # data source = average
            # type = graphite
            # destination = localhost
            # prefix = netdata
            # hostname = localhost
            # update every = 10
            # buffer on failures = 10
            # timeout ms = 20000  
    
    这一行为您找到该部分:

    perl  -lne '$b=$.; $e=($b+10) if /\[backend\]/;print if $b++<$e' file
    
    or readable version
    perl -lne 'if( /\[backend\]/ ){ $b=$.; $e=( $b+10 ); }; if( $b++ < $e ){ print }' file
    
    perl -lpe 'if(/\[backend\]/){$b=$.;$e=($b+10);};if($b++<$e){ s/#//;s/no/yes/;s/(?<=destination = ).+$/192.168.99.38:2003/;s/(?<=hostname = ).+$/\$HOSTNAME/ }' file
    
    现在,您可以使用以下内容修改该部分,而不是打印:

    s/#//;s/no/yes/;s/(?<=destination = ).+$/192.168.99.38:2003/;s/(?<=hostname = ).+$/$HOSTNAME/
    
    最后,在检查输出是否一切正常后,您可以使用
    -i
    选项使用在位编辑功能,如:

    perl-i.bak-lne'…脚本的其余部分…'文件

    .bak仅用于获取旧文件的备份。(如:file.txt.bak)


    更新以获取您的评论


    假设文本在configfile中,并且下面有另一个以“[”开头的部分,下面的解决方案应该可以工作

    sed -i '/\[backend\]/,/\[/{s/#//;s/enabled = no/enabled = yes/;s/\(destination = \)\(.*\)\($\)/\1192\.168\.99\.38\:2003\3/;s/\(hostname = \)\(.*\)\($\)/\1'$HOSTNAME'\3/}' configfile
    
    我们在[backend]和[backend]之间搜索文本,然后执行{}中包含的sed命令。我们删除#,然后编辑目标,最后编辑主机名

    如果后端下面没有其他部分,请将命令更改为:

    sed -i '/\[backend\]/,/^$/{s/#//;s/enabled = no/enabled = yes/;s/\(destination = \)\(.*\)\($\)/\1192\.168\.99\.38\:2003\3/;s/\(hostname = \)\(.*\)\($\)/\1'$HOSTNAME'\3/}' configfile
    

    假设文本在configfile中,并且下面有另一个以“[”开头的部分,下面的解决方案应该可以工作

    sed -i '/\[backend\]/,/\[/{s/#//;s/enabled = no/enabled = yes/;s/\(destination = \)\(.*\)\($\)/\1192\.168\.99\.38\:2003\3/;s/\(hostname = \)\(.*\)\($\)/\1'$HOSTNAME'\3/}' configfile
    
    我们在[backend]和[backend]之间搜索文本,然后执行{}中包含的sed命令。我们删除#,然后编辑目标,最后编辑主机名

    如果后端下面没有其他部分,请将命令更改为:

    sed -i '/\[backend\]/,/^$/{s/#//;s/enabled = no/enabled = yes/;s/\(destination = \)\(.*\)\($\)/\1192\.168\.99\.38\:2003\3/;s/\(hostname = \)\(.*\)\($\)/\1'$HOSTNAME'\3/}' configfile
    


    因此,您只想编辑
    [backend]
    下的配置(如果存在或不存在),您想编辑
    [section name
    ]下的所有部分?@k-five仅编辑
    [backend]下的部分
    ,没有其他内容。抱歉说得不够清楚,@Inian我看不到你的答案。我之前看到了一个答案,我打算应用它,但现在它不见了。@Aborted:删除了它,因为它不满足你的
    要求,只满足[backend]下的内容
    条件,立即修复您是否接受Perl one Liner?您是否只想编辑
    [后端]
    下的配置(如果存在或不存在)您想编辑
    [部分名称
    ]下的所有部分?@k-five仅编辑
    [后端]下的内容
    ,没有其他内容。抱歉说得不够清楚,@Inian我看不到你的答案。我之前看到了一个答案,我打算应用它,但现在它不见了。@Aborted:删除了它,因为它不满足你的
    要求,只满足[backend]下的内容
    条件,现在修复它您是否接受Perl one Line我不介意Perl。我相当确定它默认安装在所有Ubuntu版本上。但有一个问题:
    [无后端]
    部分是什么?@大多数Linux发行版默认都有Perl和Ubuntu。
    [无后端]
    只是另一个不应该匹配的部分,当然,很抱歉,我没有得到。非常感谢您的帮助!@没问题:)另一个问题:我不想要文本
    $HOSTNAME
    字符串。
    $HOSTNAME
    将是一个包含系统主机名的系统变量。您的Perl脚本是否连接这个变量还是将文字表达式放在那里?我不介意Perl。我相当确定它默认安装在所有Ubuntu版本上。但有一个问题:
    [无后端]
    部分是什么?@大多数Linux发行版默认都有Perl和Ubuntu。
    [无后端]
    只是另一个不应该匹配的部分,当然,很抱歉,我没有得到。非常感谢您的帮助!@没问题:)另一个问题:我不想要文本
    $HOSTNAME
    字符串。
    $HOSTNAME
    将是一个包含系统主机名的系统变量。您的Perl脚本是否连接这个变量或把li