【问题标题】:grep in a searched pattern and replace if the pattern doesn't existgrep 在搜索的模式中,如果模式不存在则替换
【发布时间】:2013-07-02 09:23:47
【问题描述】:

我有一个格式如下的文件:

========================================================
line1line1line1line1line1line1line1line1line1

line2-anything could be here

...anything again

++++++++++++++++++++++++++++++++++++++++++++++++++++++++

========================================================

abc abc abc bacbk kjhhjkh

line2-anything could be here SOME_STRING

...anything again

++++++++++++++++++++++++++++++++++++++++++++++++++++++++

我想搜索并替换块(定义在=====* 和++++* 之间)为abc,其中SOME_STRING 不存在。例如,上面的文件看起来像:

========================================================

abc

++++++++++++++++++++++++++++++++++++++++++++++++++++++++

========================================================

abc abc abc bacbk kjhhjkh

line2-anything could be here SOME_STRING

...anything again

++++++++++++++++++++++++++++++++++++++++++++++++++++++++

因为块 1 没有 SOME_STRING。

我可以使用搜索模式获取块

========================================================\_.\{-\}++++++++++++++++++++++++++++++++++++++++++++++++++++++++

但是我想 grep 这个模式搜索的结果,如果 grep 返回 1(未找到匹配项),则将块替换为 abc。

有可能吗?提前致谢。

【问题讨论】:

    标签: shell vim replace sed


    【解决方案1】:

    不知道怎么用实现,所以删帖试试:

    script.sed的内容:

    ## For all lines between these patterns...
    /^====/,/^++++/ { 
        ## Add current line to "hold space"
        H   
    
        ## Process next one unless reach to end of range.
        /^++++/! { b } 
    
        ## Get content of "hold space"
        x   
    
        ## Remove leading newline added by previous "H" command.
        s/^\n//
    
        ## If not found the string, do the removal saving either
        ## header and footer.
        /SOME_STRING/! { 
            s/^\(=\+\n\).*\(\n+\+\)$/\1abc\2/ 
        }   
    
        ## Print and remove all content from both buffers.
        p   
        s/^.*$//
        x   
        s/^.*$//
    }
    

    假设以下输入文件 (infile):

    ========================================================
    line1line1line1line1line1line1line1line1line1
    line2-anything could be here
    ...anything again
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    
    ========================================================
    abc abc abc bacbk kjhhjkh
    line2-anything could be here SOME_STRING
    ...anything again
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    
    ========================================================
    abc abc abc bacbk kjhhjkh
    line2-anything could be here SOME_STRING
    ...anything again
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    ========================================================
    line1line1line1line1line1line1line1line1line1
    line2-anything could be here
    ...anything again
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    

    像这样运行它:

    sed -nf script.sed infile
    

    产生:

    ========================================================
    abc
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    ========================================================
    abc abc abc bacbk kjhhjkh
    line2-anything could be here SOME_STRING
    ...anything again
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    ========================================================
    abc abc abc bacbk kjhhjkh
    line2-anything could be here SOME_STRING
    ...anything again
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    ========================================================
    abc
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    

    【讨论】:

    • 我猜这实际上会将具有字符串 SOME_STRING 的块替换为 abc。我想替换 SOME_STRING 不存在的块。运算符 [^some_char] 适用于角色,但在这里我需要“除 SOME_STRING 之外的任何内容”
    • @SaurabhDhir:哦,这是真的。对不起。我会努力解决的。
    • @SaurabhDhir:我尝试在最后使用sed,而不是vim。这样对我来说似乎更容易。
    • sed可以做到吗?我没有写出一个模式,我可以做一个“除了字符串 SOME_STRING 之外的任何东西”。 BTW Anubhava 使用 awk 的解决方案运行良好。
    • @SaurabhDhir:我不知道你是什么意思。我已经用sed 解决方案更改了答案。
    【解决方案2】:

    grep 不是解决此问题的正确工具。像这样使用 awk:

    awk 'c &&  $0 != "++++"{ l=l $0 RS }
         /====/{ print; c=1 } 
         c && $0 == "++++"{
           if (l ~ /SOME_STRING/)
              print l $0;
           else
              print "abc" RS $0;
           c=0;
           l=""
         }' file
    

    PS:为了向您展示代码,我将上面代码中的 =================== 和 ++++++++++++++++ 截断为长度 4。

    说明:

    /====/{ print; c=1 }    - If input matches "====" then print the line and set c=1
    c && !($0 ~ /\+\+\+\+/) - If c=1 and input doesn't match "++++" then don't print but append 
                              current line into a buffer (l=l $0 RS)
    c && $0 ~ /\+\+\+\+/ - If c=1 and input matches then execute below block:
       if (l ~ /SOME_STRING/) - if SOME_STRING is in buffer then print buffer + current line
       else                   - print abc + current line
       c=0;l=""               - reset our variables
    

    【讨论】:

    • 感谢您的回复,但是用 sed 或 vim 不可能吗?我不明白 awk。
    • awk 非常神秘。你能概述一下你的方法吗?!没有它,你的固定解决方案就没有什么可学习的了。
    • @IngoKarkat:如果 awk 是神秘的,那么 sed 将是神秘的 10 倍:P
    • @anubhava:非常感谢。它工作得很好。我知道 awk 的基本命令,但无法理解这里的命令。你能详细说明你的代码吗?再次感谢
    • 确定添加解释。
    猜你喜欢
    • 1970-01-01
    • 2017-05-11
    • 2010-11-19
    • 2011-02-25
    • 1970-01-01
    • 2021-06-22
    • 1970-01-01
    • 2016-05-18
    相关资源
    最近更新 更多