【问题标题】:sed process multiple lines in one passsed 一次处理多行
【发布时间】:2021-09-12 05:45:25
【问题描述】:

我在文件中有两行,如下所示:

#foo:
#   bar=<need replacement>

当第一行以foo 开头且第二行包含bar 并替换&lt;&gt; 之间的文本时,我想删除两行的#(如果存在)(取消注释该行) .

我可以使用 sed 在 N;P;D 循环中一次性完成此操作吗?或者还有其他更简单的方法吗?

【问题讨论】:

    标签: shell sed syntax


    【解决方案1】:

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

    sed -E '/^#?foo/{N;/\n.*bar/{s/^#//mg;s/(\n.*<).*(>.*)/\1replace\2/};P;D}' file
    

    如果当前行以foo 开头已注释或未注释,则:

    • 添加下面一行

    • 如果以下行包含单词bar,则:

      • 删除两行中的任何前导#
      • 将第二行中&lt;&gt; 之间的任何字符替换为replace
    • 打印/删除两行中的第一行并重复。

    注意这允许处理前导foo,后跟另一个前导foo,后跟bar

    【讨论】:

      【解决方案2】:

      使用带有标准 N;…;P;D; 循环和基本正则表达式的 POSIX (BRE):

      sed -e '$!N' -e '/^#\(foo:\n\)#\([[:blank:]]*bar\)=.*/ s//\1\2=newvalue/' -e P -e D < file
      

      【讨论】:

        【解决方案3】:

        也许可以做到,但我会使用不同的工具。 awk 怎么样?

        awk -v replace="new value" 'm && /^[^:]+:/ { m=0 }
          /^#foo:/ { m=1 }
          m { sub(/^#/, ""); s(/<[^<>]*>/, replace) }1' 
        

        这遵循熟悉的模式,当我们看到感兴趣区域的开始时设置状态变量m,当我们在该区域中时执行替换,当我们看到新区域的开始时关闭变量(推测这可能是什么样的条件)。

        改变它来简单地在区域开始后查找固定数量的行并不难;将状态变量设置为一个数字,并为每一行递减它。

        如果这是一个 Makefile,那么使用 make 变量会更加优雅和强大。

        ifdef ENABLE
        foo:
            bar=$(barvalue)
        endif
        

        (或者可能只是ifdef barvalue!)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-08-23
          • 1970-01-01
          • 1970-01-01
          • 2021-06-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-15
          相关资源
          最近更新 更多