【问题标题】:Matching strings even if they start with white spaces in SED匹配字符串,即使它们在 SED 中以空格开头
【发布时间】:2014-04-28 19:41:20
【问题描述】:

我在匹配字符串时遇到问题,即使它们以任意数量的空格开头。我开始使用正则表达式的时间很短,所以我需要一些帮助

这是一个例子。我有一个包含两行的文件(file.txt)

#String1='Test One'
String1='Test Two'

我正在尝试更改第二行的值,而不影响第 1 行,所以我使用了这个

sed -i "s|String1=.*$|String1='Test Three'|g"

这会更改两行的值。如何使 sed 仅更改第二个字符串的值?

谢谢

【问题讨论】:

    标签: sed spaces substitution


    【解决方案1】:

    使用 gnu sed,您可以使用 \s 匹配空格,而其他 sed 实现通常使用 [[:space:]] 字符类。因此,请选择以下之一:

    sed 's/^\s*AWord/AnotherWord/'
    sed 's/^[[:space:]]*AWord/AnotherWord/'
    

    由于您使用的是-i,我假设是 GNU sed。无论哪种方式,您可能都不应该重新输入您的单词,因为这会引入拼写错误的机会。我会选择:

    sed -i "s/^\(\s*String1=\).*/\1'New Value'/" file
    

    如果您不想保留前导空格,请将 \s* 移到括号之外。

    【讨论】:

    • 我不应该为此使用 sed 中的 g 标志吗?
    • g 标志表示您希望在一行中匹配模式的所有实例。您的模式与整行匹配,因此该行上的模式只能有零个或一个实例。因此,g 标志在这种情况下是无关紧要的。您正在考虑要匹配多行,除非您通过指定行选择器/范围选择器或类似方式来限制它,否则 sed 已经这样做了。
    【解决方案2】:

    您可以使用几种解决方案来解决您的问题

    如果您想忽略以“#”等注释字符开头的行,您可以使用以下内容:

    sed -i "/^\s*#/! s|String1=.*$|String1='Test Three'|g" file.txt
    

    它只会在与正则表达式 /.../! 不匹配的行上运行,该正则表达式以 ^ 开头,可选的 whiltespace\s* 后跟 octothorp #

    另一种选择是将“字符串”之前的字符作为替换的一部分。这样做意味着您需要捕获\(...\) 组以将其包含在\1 的输出中

    sed -i "s|^\(\s*\)String1=.*$|\1String1='Test Four'|g" file.txt
    

    【讨论】:

    • 问题说不要更改注释字符串的值,而这里的第二个选项将更改两个值(尽管同时保持注释字符不变)。在这两种情况下,由于您要匹配整行,因此在末尾包含 \g 修饰符没有多大意义;整条线只有一个实例。 ;)
    • 我提供的两个选项都已使用 OP 的示例进行了测试,并且都没有替换注释行中的文本。这是因为两者都锚定在该行的开头。我把 |g 修饰符留在了那里,因为 OP 有它,而且我认为他有它存在的原因。
    • 我一定是在寻找不同的答案或其他东西,因为你是对的;第二个答案很好。没关系。 :)
    【解决方案3】:

    使用 GNU sed,尝试:

    sed -i "s|^\s*String1=.*$|String1='Test Three'|" file
    

    sed -i "/^\s*String1=/s/=.*/='Test Three'/" file
    

    【讨论】:

    • 如果 RHS 包含 = 字符,则第二个选项将无法按预期工作。但是,第一个是超过 90% 的 sed 用户会选择,所以这可能就是他正在寻找的答案。
    • 谢谢@dannysauer!我改进了第二个选项,以便 RHS 可以包含 = 字符..
    【解决方案4】:

    使用awk 你可以这样做:

    awk '/String1/ && f++ {$2="Test Three"}1' FS=\' OFS=\' file
    #String1='Test One'
    String1='Test Three'
    

    它将忽略string1 的首次点击,因为f 不正确。

    【讨论】:

    • 如果有人给一个减号,我很高兴知道为什么,这样我可以从中学习。
    • 可能是因为问题被标记为sed 而不是awk。使用其他语言/技术而不是要求的解决方案通常会获得反对意见。我不是说它是对的,我只是说'
    • 还有观察到,这个答案实际上替换了 String1 的第二个(以及任何后续)实例,而不是跳过注释版本。而且它不需要 String1 在 LHS 上或只是 String1 - 所以它会匹配诸如“String10='pie'”和“cows='NotString1'”之类的东西。我个人倾向于使用= 作为记录分隔符并将$1 与/^[[:space:]]*String1$/ 匹配。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-10
    • 2018-02-24
    • 2014-01-15
    • 1970-01-01
    相关资源
    最近更新 更多