相对于包含模式的行,删除前面的 n1 行和后面的 n2 行

发布于 2025-01-08 16:37:56 字数 261 浏览 0 评论 0原文

sed -e '/XXXX/,+4d' fv.out

我必须在文件中找到特定模式并同时删除其上方 5 行和下方 4 行。我发现上面的行删除了包含图案的行及其下面的四行。

sed -e '/XXXX/,~5d' fv.out

在 sed 手册中,给出 ~ 代表模式后面的行。但当我尝试时,删除的是模式后面的行。

那么,如何同时删除包含该模式的行上方 5 行和下方 4 行呢?

sed -e '/XXXX/,+4d' fv.out

I have to find a particular pattern in a file and delete 5 lines above and 4 lines below it simultaneously. I found out that the line above removes the line containing the pattern and four lines below it.

sed -e '/XXXX/,~5d' fv.out

In sed manual it was given that ~ represents the lines which is followed by the pattern. But when i tried it, it was the lines following the pattern that was deleted.

So, how do I delete 5 lines above and 4 lines below a line containing the pattern simultaneously?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

才能让你更想念 2025-01-15 16:37:56

使用 sed 的一种方法,假设模式彼此不够接近:

script.sed 的内容:

## If line doesn't match the pattern...
/pattern/ ! { 

    ## Append line to 'hold space'.
    H   

    ## Copy content of 'hold space' to 'pattern space' to work with it.
    g   

    ## If there are more than 5 lines saved, print and remove the first
    ## one. It's like a FIFO.
    /\(\n[^\n]*\)\{6\}/ {

        ## Delete the first '\n' automatically added by previous 'H' command.
        s/^\n//
        ## Print until first '\n'.
        P   
        ## Delete data printed just before.
        s/[^\n]*//
        ## Save updated content to 'hold space'.
        h   
    } 

### Added to fix an error pointed out by potong in comments.
### =======================================================
    ## If last line, print lines left in 'hold space'.
    $ { 
        x   
        s/^\n//
        p   
    } 
### =======================================================


    ## Read next line.
    b   
}

## If line matches the pattern...
/pattern/ {

    ## Remove all content of 'hold space'. It has the five previous
    ## lines, which won't be printed.
    x   
    s/^.*$//
    x   

    ## Read next four lines and append them to 'pattern space'.
    N ; N ; N ; N 

    ## Delete all.
    s/^.*$//
}

运行如下:

sed -nf script.sed infile

One way using sed, assuming that the patterns are not close enough each other:

Content of script.sed:

## If line doesn't match the pattern...
/pattern/ ! { 

    ## Append line to 'hold space'.
    H   

    ## Copy content of 'hold space' to 'pattern space' to work with it.
    g   

    ## If there are more than 5 lines saved, print and remove the first
    ## one. It's like a FIFO.
    /\(\n[^\n]*\)\{6\}/ {

        ## Delete the first '\n' automatically added by previous 'H' command.
        s/^\n//
        ## Print until first '\n'.
        P   
        ## Delete data printed just before.
        s/[^\n]*//
        ## Save updated content to 'hold space'.
        h   
    } 

### Added to fix an error pointed out by potong in comments.
### =======================================================
    ## If last line, print lines left in 'hold space'.
    $ { 
        x   
        s/^\n//
        p   
    } 
### =======================================================


    ## Read next line.
    b   
}

## If line matches the pattern...
/pattern/ {

    ## Remove all content of 'hold space'. It has the five previous
    ## lines, which won't be printed.
    x   
    s/^.*$//
    x   

    ## Read next four lines and append them to 'pattern space'.
    N ; N ; N ; N 

    ## Delete all.
    s/^.*$//
}

Run like:

sed -nf script.sed infile
荒路情人 2025-01-15 16:37:56

使用awk的解决方案:

awk '$0 ~ "XXXX" { lines2del = 5; nlines = 0; }
     nlines == 5 { print lines[NR%5]; nlines-- }
     lines2del == 0 { lines[NR%5] = $0; nlines++ }
     lines2del > 0 { lines2del-- }
     END { while (nlines-- > 0)  { print lines[(NR - nlines) % 5] } }' fv.out

更新:

这是解释的脚本:

  • 我记得数组lines中的最后5行使用旋转索引(NR% 5;NR 是记录编号;在本例中为行)。
  • 如果我在当前行中找到模式($0 ~ "XXXX; $0 是当前记录:在本例中是一行;并且 ~作为扩展正则表达式匹配运算符),我重置了读取的行数,并注意到我有 5 行要删除(包括当前行),
  • 如果我已经读取了 5 行,我会打印当前行。 )
  • 如果我没有要删除的行(这也是如此 如果我读了 5 行,我会将当前行放入缓冲区并增加行数,请注意如果打印了一行
  • , 则行数如何减少然后增加。任何内容并减少要删除的行数。
  • 在脚本末尾,我打印了数组中的所有行。

我的脚本原始版本如下,但我最终将其优化为上述版本:

awk '$0 ~ "XXXX" { lines2del = 5; nlines = 0; }
     lines2del == 0 && nlines == 5 { print lines[NR%5]; lines[NR%5] }
     lines2del == 0 && nlines < 5 { lines[NR%5] = $0; nlines++ }
     lines2del > 0 { lines2del-- }
     END { while (nlines-- > 0)  { print lines[(NR - nlines) % 5] } }' fv.out

< code>awk 是一个很棒的工具我强烈建议您在网上找到一个教程并阅读它:awk 可与扩展正则表达式 (ERE) 配合使用。 。它们的语法与 sed 中使用的标准正则表达式 (RE) 略有不同,但是使用 RE 可以完成的所有操作都可以使用埃雷。

A solution using awk:

awk '$0 ~ "XXXX" { lines2del = 5; nlines = 0; }
     nlines == 5 { print lines[NR%5]; nlines-- }
     lines2del == 0 { lines[NR%5] = $0; nlines++ }
     lines2del > 0 { lines2del-- }
     END { while (nlines-- > 0)  { print lines[(NR - nlines) % 5] } }' fv.out

Update:

This is the script explained:

  • I remember the last 5 lines in the array lines using rotatory indexes (NR%5; NR is the record number; in this case lines).
  • If I find the pattern in the current line ($0 ~ "XXXX; $0 being the current record: in this case a line; and ~ being the Extended Regular Expression match operator), I reset the number of lines read and note that I have 5 lines to delete (including the current line).
  • If I already read 5 lines, I print the current line.
  • If I do not have lines to delete (which is also true if I had read 5 lines, I put the current line in the buffer and increment the number of lines. Note how the number of lines is decremented and then incremented if a line is printed.
  • If lines need to be deleted, I do not print anything and decrement the number of lines to delete.
  • At the end of the script, I print all the lines that are in the array.

My original version of the script was the following, but I ended up optimizing it to the above version:

awk '$0 ~ "XXXX" { lines2del = 5; nlines = 0; }
     lines2del == 0 && nlines == 5 { print lines[NR%5]; lines[NR%5] }
     lines2del == 0 && nlines < 5 { lines[NR%5] = $0; nlines++ }
     lines2del > 0 { lines2del-- }
     END { while (nlines-- > 0)  { print lines[(NR - nlines) % 5] } }' fv.out

awk is a great tool ! I strongly recommend that you find a tutorial on the net and read it. One important thing: awk works with Extended Regular Expressions (ERE). Their syntax is a little different from Standard Regular Expression (RE) used in sed, but all that can be done with RE can be done with ERE.

蹲在坟头点根烟 2025-01-15 16:37:56

这个想法是读取 5 行而不打印它们。如果找到该图案,请删除未打印的行和下面的 4 行。如果没有找到该模式,请记住当前行并打印第一个未打印的行。最后,打印未打印的内容。

sed -n -e '/XXXX/,+4{x;s/.*//;x;d}' -e '1,5H' -e '6,${H;g;s/\n//;P;s/[^\n]*//;h}' -e '${g;s/\n//;p;d}' fv.out

当然,这仅当您的模式在文件中出现一次时才有效。如果你有很多,你需要在找到你的模式后阅读 5 行新的行,如果你在这些行中再次有你的模式,事情就会变得复杂。在这种情况下,我认为 sed 不是正确的工具。

The idea is to read 5 lines without printing them. If you find the pattern, delete the unprinted lines and the 4 lines bellow. If you do not find the pattern, remember the current line and print the 1st unprinted line. At the end, print what is unprinted.

sed -n -e '/XXXX/,+4{x;s/.*//;x;d}' -e '1,5H' -e '6,${H;g;s/\n//;P;s/[^\n]*//;h}' -e '${g;s/\n//;p;d}' fv.out

Of course, this only works if you have one occurrence of your pattern in the file. If you have many, you need to read 5 new lines after finding your pattern, and it gets complicated if you again have your pattern in those lines. In this case, I think sed is not the right tool.

我只土不豪 2025-01-15 16:37:56

这可能对你有用:

sed 'H;$!d;g;s/\([^\n]*\n\)\{5\}[^\n]*PATTERN\([^\n]*\n\)\{5\}//g;s/.//' file

或者这个:

awk --posix -vORS='' -vRS='([^\n]*\n){5}[^\n]*PATTERN([^\n]*\n){5}' 1 file

一个更有效的 sed 解决方案:

sed ':a;/PATTERN/,+4d;/\([^\n]*\n\)\{5\}/{P;D};$q;N;ba' file

This might work for you:

sed 'H;$!d;g;s/\([^\n]*\n\)\{5\}[^\n]*PATTERN\([^\n]*\n\)\{5\}//g;s/.//' file

or this:

awk --posix -vORS='' -vRS='([^\n]*\n){5}[^\n]*PATTERN([^\n]*\n){5}' 1 file

a more efficient sed solution:

sed ':a;/PATTERN/,+4d;/\([^\n]*\n\)\{5\}/{P;D};$q;N;ba' file
三寸金莲 2025-01-15 16:37:56

如果您愿意将结果输出到文件而不是 stdout,vim 可以非常有效地完成它:

vim -c 'g/pattern/-5,+4d' -c 'w! outfile|q!' infile

或者

vim -c 'g/pattern/-5,+4d' -c 'x' infile

就地编辑文件。

If you are happy to output the result to a file instead of stdout, vim can do it quite efficiently:

vim -c 'g/pattern/-5,+4d' -c 'w! outfile|q!' infile

or

vim -c 'g/pattern/-5,+4d' -c 'x' infile

to edit the file in-place.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文