如何获取从最后一个匹配到文件末尾的行?
Posted
技术标签:
【中文标题】如何获取从最后一个匹配到文件末尾的行?【英文标题】:How to get lines from the last match to the end of file? 【发布时间】:2022-01-08 05:44:59 【问题描述】:需要在最后一个匹配后打印行到文件末尾。匹配的数量可以是任意的,并且不是确定的。我有一些如下所示的文字。
MARKER
aaa
bbb
ccc
MARKER
ddd
eee
fff
MARKER
ggg
hhh
iii
MARKER
jjj
kkk
lll
想要的输出是
jjj
kkk
lll
我是否将 awk 与 RS 和 FS 一起使用以获得所需的输出?
【问题讨论】:
我在awk
解决方案之上添加了grep
和sed
解决方案。
所需的输出是否还包含MARKER
或只是您显示的内容?
@Allan 没有问题。谢谢。我在 perl 脚本中使用您答案中的第一个命令。 Perl 脚本将 $0 解释为脚本名称,而不是直到 EOF 的行。有没有办法解决这个问题?
@Allan 这是我的 perl 脚本中的行 "$data = `zcat file.gz | awk -v RS='MARKER\n' 'ENDprintf $0' | grep 'Data : '`"
@Allan 没关系。我必须逃脱$ 0。 printf \$0
【参考方案1】:
您实际上可以使用 awk
(gawk) 来完成此操作,而无需使用任何管道。
$ awk -v RS='(^|\n)MARKER\n' 'ENDprintf "%s", $0' file
jjj
kkk
lll
说明:
您通过RS='(^|\n)MARKER\n'
将记录分隔符定义为(^|\n)MARKER\n
,默认为EOL
字符
'ENDprintf "%s", $0'
=> 在文件末尾,打印整行,因为 RS
设置为 (^|\n)MARKER\n
,$0
将包括所有行,直到 EOF。
另一种选择是使用
grep
(GNU):
$ grep -zoP '(?<=MARKER\n)(?:(?!MARKER)[^\0])+\Z' file
jjj
kkk
lll
说明:
-z
使用 ASCII NUL 字符作为分隔符
-o
仅打印匹配项
-P
激活 perl 模式
PCRE 正则表达式:(?<=MARKER\n)(?:(?!MARKER)[^\0])+\Z
在这里解释https://regex101.com/r/RpQBUV/2/
最后但同样重要的是,还可以使用以下
sed
方法:
sed -n '/^MARKER$/n;h;b;H;$x;p' file
jjj
kkk
lll
说明:
n
跳到下一行
h
用当前行替换保持空间
H
做同样的事情,但不是替换,而是追加
$x;p
在文件交换结束时 (x
) 保留空间和模式空间并打印 (p
)
可以变成:
tac file | sed -n '/^MARKER$/q;p' | tac
如果我们使用tac
。
【讨论】:
【参考方案2】:请您尝试关注一下。
tac file | awk '/MARKER/print val;exit val=(val?val ORS:"")$0' | tac
这种方法的好处是awk
将只读取 Input_file 的最后一个块(这实际上是awk
在tac
反向打印之后的第一个块)并在此之后退出。
解释:
tac file | ##Printing Input_file in reverse order.
awk '
/MARKER/ ##Searching for a string MARKER in a line of Input_file.
print val ##Printing variable val here. Because we need last occurrence of string MARKER,which has become first instance after reversing the Input_file.
exit ##Using exit to exit from awk program itself.
val=(val?val ORS:"")$0 ##Creating variable named val whose value will be keep appending to its own value with a new line to get values before string MARKER as per OP question.
' | ##Sending output of awk command to tac again to make it in its actual form, since tac prints it in reverse order.
tac ##Using tac to make it in correct order(lines were reversed because of previous tac).
【讨论】:
谢谢,成功了!!你能解释一下awk代码吗? @Arteezy,很高兴它对你有所帮助,现在为我的代码添加了完整的解释,干杯。 @Arteezy:我也添加了一个 grep 解决方案!【参考方案3】:你也可以试试 Perl
$ perl -0777 -ne ' /.*MARKER(.*)/s and print $1 ' input.txt
jjj
kkk
lll
$
【讨论】:
【参考方案4】:这可能对你有用(GNU sed):
sed -nz 's/.*MARKER.//p' file
这使用贪婪删除所有行,包括最后一次出现的MARKER
。
【讨论】:
【参考方案5】:最简单的记忆:
tac fun.log | sed "/MARKER/Q" | tac
【讨论】:
【参考方案6】:此awk
解决方案适用于任何操作系统上的任何awk
版本:
awk '/^MARKER$/ s=""; next s = s $0 RS END printf "%s", s' file
jjj
kkk
lll
【讨论】:
以上是关于如何获取从最后一个匹配到文件末尾的行?的主要内容,如果未能解决你的问题,请参考以下文章