【问题标题】:use sed to match on string but not remove anything past any number of specific characters then a character使用 sed 匹配字符串,但不删除任何数量的特定字符之后的任何内容,然后是一个字符
【发布时间】:2022-01-19 22:50:22
【问题描述】:

这是一个名为“config_file.txt”的示例文件:

setting01 = 0          # Comment for setting 01
setting02 = 1          # Comment for setting 02
setting03 = "./folder" # Comment for setting 03
setting04 = "string"   # Comment for setting 04
setting05 = 1          # Comment for setting 05

我需要替换每个设置,但设置后不影响任何内容。这意味着不要删除设置后的任何空格、“#”以及“#”之后的任何内容。

我尝试了以下替换“setting01”

sed -i "s/setting01\\ =\\ .*#/setting01\\ = 1/g" conf_file.txt

然而结果是这样的:

setting01 = 1 Comment for setting 01
setting02 = 1          # Comment for setting 02
setting03 = "./folder" # Comment for setting 03
setting04 = "string"   # Comment for setting 04
setting05 = 1          # Comment for setting 05

当我想要这个时:

setting01 = 1          # Comment for setting 01
setting02 = 1          # Comment for setting 02
setting03 = "./folder" # Comment for setting 03
setting04 = "string"   # Comment for setting 04
setting05 = 1          # Comment for setting 05

我怎样才能做到这一点?

【问题讨论】:

    标签: regex sed replace


    【解决方案1】:

    你可以使用

    sed -i -E 's/(setting01 = )("[^"]*"|[^[:space:]]+)/\11/g' conf_file.txt
    

    详情

    • -E - 启用 POSIX ERE 正则表达式语法
    • (setting01 = ) - 第 1 组:setting01 =
    • ("[^"]*"|[^[:space:]]+) - 第 2 组:
      • "[^"]*" - ",然后是 " 以外的零个或多个字符,然后是 "
      • | - 或
      • [^[:space:]]+ - 一个或多个非空白字符

    \11 将匹配替换为 Group 1 值和 1(因为在 POSIX 正则表达式中不能有超过 \9 反向引用,\11 不会被 sed 解析为第 11 个反向引用) .

    online demo

    #!/bin/bash
    s='setting01 = 0          # Comment for setting 01
    setting02 = 1          # Comment for setting 02
    setting03 = "./folder" # Comment for setting 03
    setting04 = "string"   # Comment for setting 04
    setting05 = 1          # Comment for setting 05'
     
    sed -E 's/(setting01 = )("[^"]*"|[^[:space:]]+)/\11/g'  <<< "$s"
    

    输出:

    setting01 = 1          # Comment for setting 01
    setting02 = 1          # Comment for setting 02
    setting03 = "./folder" # Comment for setting 03
    setting04 = "string"   # Comment for setting 04
    setting05 = 1          # Comment for setting 05
    

    【讨论】:

    • 非常酷!知道,我没有提到它,但是我使用 bash 循环处理所有配置值更改实际循环执行此操作($i 是要从数组中更改为的值,其中数组中的每个值都是“settingX = NewValue”) . $val 是一个包含" 围绕字符串的值的清理版本。 sed -i -E "s/(${i%=*} = )(\"[^\"]*\"|[^[:space:]]+)/${i%=*}\\ = $val/g" $conf 经过测试,这完全符合我的需要。
    • @Dave 您也可以使用's/('"${i%=*}"' = )("[^"]*"|[^[:space:]]+)/\1'"$val"'/g' 之类的串联。顺便说一句,您不需要转义文字空格。
    【解决方案2】:

    这可能对你有用(GNU sed):

    sed -E '/^(setting03 = )(\S+)/{s//\1\nXXX\n\2/
             :a;ta;s/(\n.*\n *)[^ #]/\1 /;ta
             :b;tb;s/\n(\S)(.*\n) /\1\n\2/;tb
             s/\n#([^\n]*)$/ #\1/;s/\n//g;s/ +$//}' file
    

    通过设置-E 命令行选项打开扩展正则表达式。

    替换setting03 的值,在前面加上一个换行符并附加另一个换行符和原始值(用作模板)。

    用空格替换模板,然后将新值叠加在上面。

    删除换行标记,如果新值大于注释前的空格,则附加一个额外的空格以将其与注释分开。

    最后,如果原始行没有注释,请删除空格。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-22
      • 1970-01-01
      • 2020-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多