【问题标题】:Replacement within the matched string with sed用 sed 替换匹配的字符串
【发布时间】:2017-03-20 09:51:07
【问题描述】:

我有一个 java 的属性文件,如下所示。

server.port=8080
spring.application.name=app1
spring.datasource.driver-class-name=org.mysql.jdbc.Driver

我想将该文件转换为如下所示的 linux 等效属性文件。

SERVER_PORT=8080
SPRING_APPLICATION_NAME=app1
SPRING_DATASOURCE_DRIVER_CLASS_NAME=org.mysql.jdbc.Driver

我正在使用sed,并且可以使用以下 sed 命令转换属性名称。

sed "s/^\(.*\)=\(.*\)$/\U\1=\E\2/" application.properties

但是,我无法弄清楚如何将匹配部分(\1)中的点(.)替换为下划线(_)字符。

有人可以帮忙吗?

【问题讨论】:

    标签: regex linux replace sed


    【解决方案1】:

    如果perl 没问题:

    $ perl -pe 's/^.*=/\U$&/; s/^.*=/$&=~s|\.|_|gr/e' application.properties 
    SERVER_PORT=8080
    SPRING_APPLICATION_NAME=app1
    SPRING_DATASOURCE_DRIVER-CLASS-NAME=org.mysql.jdbc.Driver
    
    • s/^.*=/$&=~s|\.|_|gr/e 使用另一个替换捕获的文本 ^.*=

    可以简化为

    $ perl -pe 's/^.*=/uc $&=~s|\.|_|gr/e' application.properties 
    SERVER_PORT=8080
    SPRING_APPLICATION_NAME=app1
    SPRING_DATASOURCE_DRIVER-CLASS-NAME=org.mysql.jdbc.Driver
    


    sed

    $ sed 's/^.*=/\U&/; :a s/^\([^=]*\)\./\1_/g; ta' application.properties 
    SERVER_PORT=8080
    SPRING_APPLICATION_NAME=app1
    SPRING_DATASOURCE_DRIVER-CLASS-NAME=org.mysql.jdbc.Driver
    
    • :a s/^\([^=]*\)\./\1_/g; ta. 替换为 _ 直到 . 之前的文本不包含 =


    如果=之前的.-都需要更改为_,则在这两种解决方案中都使用[.-]而不是\.

    【讨论】:

      【解决方案2】:

      您可以使用条件循环:

      sed 's/^[^=]*/\U&/;:a;s/^\([^=]*\)[.-]/\1_/;ta'
      

      只要有东西被替换,ta 就会跳转到标签“a”。

      使用 awk:

      awk -F= -vOFS='=' '{$1=toupper($1);gsub("[-.]", "_", $1)}1'
      

      【讨论】:

        【解决方案3】:

        使用cuttrpaste 和进程替换(需要 Bash):

        $ paste -d= <(cut -f1 -d= application.properties | tr '[:lower:].-' '[:upper:]_') \
        >           <(cut -f2 -d= application.properties)
        SERVER_PORT=8080
        SPRING_APPLICATION_NAME=app1
        SPRING_DATASOURCE_DRIVER_CLASS_NAME=org.mysql.jdbc.Driver
        

        cutpaste 都使用= 作为分隔符,第一个cut 通过管道连接到tr,用于大写和用下划线替换句点和破折号。

        【讨论】:

        • ++ 为了概念上的简单性,即使涉及多个子进程(在这种情况下可能无关紧要)。
        【解决方案4】:

        另一个perl 解决方案在概念上可能更简单:@Sundeep 致敬,感谢他在简化命令方面的帮助。

        perl -F'(=)' -ane '$F[0] = uc $F[0] =~ tr/./_/r; print @F' application.properties
        
        • -F(=)-a 结合使用,将每个输入行拆分为= 的字段。 (-n 禁止默认输出,-e 告诉 Perl 将下一个操作数视为 命令)。
          (...) 中包含= 也会使= 实例成为存储在@F 中的字段数组的一部分。

        • $F[0] =~ tr/./_/r 翻译所有文字 . 字符。进入_ 字符。在第一个字段(属性名称)中并返回结果,这要归功于r 选项。

        • $F[0] = uc 然后将结果转换为全大写并用结果更新第一个字段。

        • print @F 然后打印所有字段,从修改后的第一个字段开始,用= 分隔(在@F 中也捕获的输出字段分隔符),实际上打印大写的第一个输入带有. 字符的字段。翻译成_,然后是=和输入行的未修改的剩余部分。

        【讨论】:

        • 好一个,也可以用perl -F'/(=)/' -ane '$F[0] =~ tr/./_/; $F[0] = uc $F[0]; print @F'
        • 同样,使用r修饰符 --> $F[0] = uc $F[0] =~ tr/./_/r
        • -F'(=)' 表示分隔符= 也保存在@F 数组中...检查perl -F'(=)' -lane 'print $F[1]' vs perl -F'=' -lane 'print $F[1]'
        • @Sundeep:知道了;我对使用带有-F 的捕获组的作用有一个误解;现在更正了。并回答我自己的问题:split function 的帮助主题中描述了与 -F 一起使用的捕获组将分隔符添加到字段数组中。
        • 可能是因为print @F 仍然需要一个循环并使用$,,无论如何我们都在用join 做类似的事情.. 但捕获分隔符会产生额外的惩罚..
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-12-18
        • 1970-01-01
        • 2020-07-28
        • 2016-04-29
        • 1970-01-01
        • 2020-03-13
        • 1970-01-01
        相关资源
        最近更新 更多