sed -e '/XXXX/,+4d' fv.out
我必须在一个文件中find一个特定的模式,同时删除上面5行和下面4行。 我发现上面的这行删除了包含模式的行和它下面的四行。
sed -e '/XXXX/,~5d' fv.out
在sed手册中给出〜表示模式后面的行。 但是当我尝试它时,它是被删除的模式之后的行。
那么,如何同时删除含有该模式的行的上面5行和下面的4行呢?
一种使用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'. $ { xs/^\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. xs/^.*$// x ## Read next four lines and append them to 'pattern space'. N ; N ; N ; N ## Delete all. s/^.*$// }
运行如下:
sed -nf script.sed infile
这个想法是读5行而不打印它们。 如果找到图案,请删除未打印的线条和下面四行。 如果没有找到图案,请记住当前行并打印第一条未打印的行。 最后,打印什么是未打印的。
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不是正确的工具。
使用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行。 $0 ~ "XXXX
; $0
是当前记录:在这种情况下是行;并且是扩展正则表达式匹配运算符)中找到该模式,则重置读取的行数并注意到删除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
awk
是一个伟大的工具! 我强烈建议您在网上找到一个教程,并阅读它。 一个重要的事情: awk
与扩展正则表达式 ( ERE )一起工作。 它们的语法与sed
使用的标准正则表达式 ( RE )有些不同,但是可以用ERE完成所有可以用RE完成的语法。
这可能适合你:
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
如果你很乐意将结果输出到一个文件而不是标准输出, vim
可以非常有效地完成:
vim -c 'g/pattern/-5,+4d' -c 'w! outfile|q!' infile
要么
vim -c 'g/pattern/-5,+4d' -c 'x' infile
在原地编辑文件。