【问题标题】:sed remove first pattern match onlysed 仅删除第一个模式匹配
【发布时间】:2015-05-07 12:01:43
【问题描述】:

我想匹配两个模式之间的一组数据,并删除这些数据和开始/结束模式,但仅限于模式的第一次出现。

所以如果这是测试数据:

PATTERNSTART
LINE1
LINE2
LINE3
PATTERNEND
PATTERNSTART
LINE1
LINE2
LINE3
PATTERNEND
TESTLINE1
TESTLINE2
TESTLINE3
PATTERNSTART
LINE1
LINE2
LINE3
PATTERNEND

这会很高兴删除所有模式匹配和中间的行,但我只想删除第一个模式匹配和中间的行:

sed '/PATTERNSTART/,/PATTERNEND/d' testsed.txt

输出:

TESTLINE1
TESTLINE2
TESTLINE3

需要的输出:

PATTERNSTART
LINE1
LINE2
LINE3
PATTERNEND
TESTLINE1
TESTLINE2
TESTLINE3
PATTERNSTART
LINE1
LINE2
LINE3
PATTERNEND

任何 sed 想法?

【问题讨论】:

    标签: sed


    【解决方案1】:

    这有点不可思议 - 机器,但这是可行的:

    sed '/PATTERNSTART/,/PATTERNEND/ { // { x; s/$/./; x; }; x; /.../! { x; d; }; x; }' filename
    

    如下:

    /PATTERNSTART/,/PATTERNEND/ {   # in the pattern range
      // {                          # in the first and last line:
        x
        s/$/./                      # increment a counter in the hold buffer by
                                    # appending a character to it. The counter is
                                    # the number of characters in the hold buffer.
        x
      }
      x                             # for all lines in the range: inspect the
                                    # counter
      /.../! {                      # if it is not three or more (the counter
                                    # becomes three with the start line of the
                                    # second matching range)
        x
        d                           # delete the line
      }
      x
    }
    

    该代码中的xs 主要是为了确保当整个事情结束时计数器最终回到保持缓冲区中。 // 位有效,因为 // 重复上次尝试的正则表达式,这是其第一行的范围的开始模式和其他行的结束模式。

    【讨论】:

    • 它确实有效@Wintermute,如果模式之间的线条在数量上发生变化,它仍然有效。 /.../! 是什么意思?做?如果什么不是三个或更多?
    • x 交换模式空间和保持缓冲区。 // { x; s/$/./; x; } 位通过将另一个字符附加到匹配范围的每个边界行的保持缓冲区中来在保持缓冲区中保留一个计数器——计数器是保持缓冲区中的字符数。 x; /.../! { x; d; } 检查模式空间并执行x; d;(即,换回并删除该行)如果其内容不匹配(这就是! 的用途)与正则表达式... 匹配,当它包含三个或更多字符 - 即,当计数器为三个或更高时。
    【解决方案2】:

    只需使用 awk(cat -n 只是为了让您可以看到正在打印的行号):

    $ cat -n file | awk '/PATTERNSTART/{f=1;++c} !(f && c==1); /PATTERNEND/{f=0}'
         6  PATTERNSTART
         7  LINE1
         8  LINE2
         9  LINE3
        10  PATTERNEND
        11  TESTLINE1
        12  TESTLINE2
        13  TESTLINE3
        14  PATTERNSTART
        15  LINE1
        16  LINE2
        17  LINE3
        18  PATTERNEND
    

    c 上的测试设置为您要跳过的任何块的出现次数:

    $ cat -n file | awk '/PATTERNSTART/{f=1;++c} !(f && c==2); /PATTERNEND/{f=0}'
         1  PATTERNSTART
         2  LINE1
         3  LINE2
         4  LINE3
         5  PATTERNEND
        11  TESTLINE1
        12  TESTLINE2
        13  TESTLINE3
        14  PATTERNSTART
        15  LINE1
        16  LINE2
        17  LINE3
        18  PATTERNEND
    

    【讨论】:

      【解决方案3】:
      sed '/PATTERNSTART/,/PATTERNEND/{0,/PATTERNEND/d}' file
      

      【讨论】:

        【解决方案4】:

        你可以用那个(我承认很丑)sed代码来做到这一点:

        sed -e '/PATTERNSTART/,/PATTERNEND/{ /PATTERNEND/b after; d; :after; N; s/^.*\n//; :loop; n; b loop; }' testsed.txt
        

        让我们更仔细地看一下:

        sed -e '/PATTERNSTART/,/PATTERNEND/{
        
         /PATTERNEND/b after; # if we're at the end of match, go to the hack
         d;                   # if not, delete the line and start a new cycle
        
         :after;              # Begin "end of part to delete"
         N;                   # get the next line...
         s/^.*\n//;           # ...and forget about this one
        
                              # We now only have to print everything:
         :loop; n; b loop;
        
                              # And you sir, have your code!
        }' testsed.txt
        

        【讨论】:

          【解决方案5】:

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

          sed '/PATTERNSTART/,/PATTERNEND/{x;/./{x;b};x;/PATTERNEND/h;d}' file
          

          这将保持空间用作开关。检查文件以获取所需的行范围。如果遇到并且保留空间不为空,则第一个范围已被删除,因此请退出并正常打印。如果没有,请在最后一个模式匹配上设置开关并删除范围内的所有行。

          【讨论】:

            【解决方案6】:

            使用

            sed -e '/PATTERNSTART/,/PATTERNEND/d' -e '/PATTERNEND/q' some_file.txt
            

            q 命令导致sed 退出。

            【讨论】:

            • q 是否需要单独的模式匹配或 {d;q} 是否适用于该范围?
            • @EtanReisner 如果你把它放在范围内,那么一旦它看到PATTERNSTART,它将删除该行然后退出
            • 这对你有用吗?对我来说,这似乎与 OP 具​​有相同的输出。我的建议也是如此。 sed 4.1.5
            • sed 是“贪婪的”,因此它会在删除所有给出相同结果的模式后退出。
            • d 在下一行开始一个新循环,因此永远不会到达/PATTERNEND/q
            猜你喜欢
            • 1970-01-01
            • 2020-08-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-11-24
            • 1970-01-01
            • 2020-02-09
            • 1970-01-01
            相关资源
            最近更新 更多