我希望在模式最后一次出现之后删除除模式本身之外的所有行
file.txt的
honor
apple
redmi
nokia
apple
samsung
lg
htc
file.txt我想要的是什么
honor
apple
redmi
nokia
apple
我尝试了什么
sed -i '/apple/q' file.txt
这会在第一次出现模式后删除所有行 -
honor
答案 0 :(得分:6)
使用几乎没有内存的简单,强大的2遍方法:
$ awk 'NR==FNR{if (/apple/) hit=NR; next} {print} FNR==hit{exit}' file file
honor
apple
redmi
nokia
apple
如果执行速度不够快那么,是时候尝试一些替代方案,看看是否会产生性能提升。
答案 1 :(得分:3)
反转文件,从第一次出现的模式开始打印所有内容,然后反转结果:
tac file.txt | sed -n '/apple/,$p' | tac > newfile.txt
您可以找到最后一个匹配的行号,然后用它来打印文件的前N行:
line=$(awk '/apple/ { line=NR } END {print line}')
head -n $line file.txt > newfile.txt
答案 2 :(得分:1)
如果您不想像Barmar建议的那样反转文件,您将需要使用较低级别的工具(例如,fseek)反向读取文件或阅读两次:
sed $(awk '/apple/{a=NR}END{print a+1}' input),\$d input
(请注意,如果模式没有出现在文件中,则不会输出任何内容。这是您应该担心的边缘情况。)
答案 3 :(得分:1)
这可能适合你(GNU sed):
sed '/apple/,$!b;//!H;//{x;//p;x;h};${x;P};d' file
照常打印任何非apple
首次出现到文件末尾的行。对于上述范围内的行,将不包含单词apple
的行附加到保留空间(HS)。包含单词apple
的行,首先交换到HS,如果单词apple
在那里则打印任何行,然后将HS替换为包含apple
的行。删除最后一行以外的所有行。在文件末尾打印HS的第一行并删除剩余的行。
如果啜饮大文件不是问题,请使用:
sed -rz 's/(.*apple[^\n]*).*/\1\n/' file
这使用贪婪来捕捉单词apple
之前的所有行。
答案 4 :(得分:0)
这是另一个awk
没有扫描文件两次
$ awk 'f {buf=buf ORS $0}
/apple/ {f=1; if(buf)print buf; buf=$0}
!f' file
honor
apple
redmi
nokia
apple
答案 5 :(得分:0)
如果你不介意记忆中的一切,你可以这样做:
$ awk '/^apple$/{last=NR}
{lines[NR]=$0}
END{for(li=1;li<=last;li++) print lines[li]}' file
honor
apple
redmi
nokia
apple
答案 6 :(得分:0)
鉴于您正在处理大量输入,我会使用两遍coreutils
解决方案,例如:
n=$(grep -Fn apple infile | tail -n1 | cut -d: -f1)
[ -n "$n" ] && head -n$n infile > outfile
这使用 grep的固定字符串匹配(-F
)来查找包含苹果的每一行。然后 head 用于提取相关行。
您未指定未找到苹果时会发生什么,因此此解决方案在发生时无效。