在不读取整个文件的情况下以相反的顺序 Grep
Grep in reverse order without reading whole file
我有一个可能非常大的日志文件 (10+ GB)。我想找到表达式的最后一次出现。是否可以使用标准 posix 命令执行此操作?
以下是一些类似问题的可能答案,但不太合适。
- 使用
tail -n <x> <file> | grep -m 1 <expression>
:我不知道表达式有多远,所以我不知道<x>
会是什么。它可能是几 GB 之前,所以你会拖尾整个文件。我想你可以循环并递增 <x>
直到找到它,但是你会重复读取文件的最后一部分。
- 使用
tac <file> | grep -m 1 <expression>
:tac读取整个源文件。一旦找到某些输出,就可以将某些东西链接到 sigkill tac 上吗?这样有效率吗?
- 使用awk/sed:我很确定这些都是从文件的顶部开始的(虽然我可能错了,我的sed-fu不强)。
- "There'd be no speed up so why bother":我认为这是不正确的,因为文件系统可以在不读取整个文件的情况下查找文件的末尾。需要进行一些试验,error/buffering 才能找到每一行,但与读取(例如)从未使用过的 10 GB 相比,这不会减慢速度。
- 写一个 python/perl 脚本来完成它:如果没有人能提出更好的建议,这就是我的后备方案。我宁愿坚持可以直接通过命令行完成的事情,因为我直接通过 ssh 执行它,而且我也宁愿不必上传脚本文件。在 python 中使用 mmap 的 rfind(),我认为我们可以在几行内完成,前提是要查找的表达式是静态的(不幸的是,我的不是)。正则表达式需要更多的工作,比如 this.
如果有帮助,表达式将锚定在行首,例如:"^foo \d+$"
.
无论您编写什么脚本,几乎肯定会比以下脚本慢:
tac file | grep -m 1 '^foo [0-9][0-9]*$'
此 awk
脚本将搜索整个文件并打印匹配给定 /pattern/
:
的最后一行
$ awk '/pattern/ { line=[=10=] } END { print $line }' gigantic.log
使用 tac
将是一个更好的选择(这使用 GNU sed
输出第一个(即最后一个)找到的匹配 '/pattern/',之后它终止,终止管道):
$ tac gigantic.log | gsed -n '/pattern/{p;q}'
使用 Perl 或 C 或其他语言,您可以查找到文件末尾,后退 4kb(或其他),然后
- 向前读4kb,
- 后退8kb
- 重复直到找到模式,确保正确处理读取部分行。
(这个,除了寻找模式,实际上可能是 tac
所做的:one implementation of tac
)
我有一个可能非常大的日志文件 (10+ GB)。我想找到表达式的最后一次出现。是否可以使用标准 posix 命令执行此操作?
以下是一些类似问题的可能答案,但不太合适。
- 使用
tail -n <x> <file> | grep -m 1 <expression>
:我不知道表达式有多远,所以我不知道<x>
会是什么。它可能是几 GB 之前,所以你会拖尾整个文件。我想你可以循环并递增<x>
直到找到它,但是你会重复读取文件的最后一部分。 - 使用
tac <file> | grep -m 1 <expression>
:tac读取整个源文件。一旦找到某些输出,就可以将某些东西链接到 sigkill tac 上吗?这样有效率吗? - 使用awk/sed:我很确定这些都是从文件的顶部开始的(虽然我可能错了,我的sed-fu不强)。
- "There'd be no speed up so why bother":我认为这是不正确的,因为文件系统可以在不读取整个文件的情况下查找文件的末尾。需要进行一些试验,error/buffering 才能找到每一行,但与读取(例如)从未使用过的 10 GB 相比,这不会减慢速度。
- 写一个 python/perl 脚本来完成它:如果没有人能提出更好的建议,这就是我的后备方案。我宁愿坚持可以直接通过命令行完成的事情,因为我直接通过 ssh 执行它,而且我也宁愿不必上传脚本文件。在 python 中使用 mmap 的 rfind(),我认为我们可以在几行内完成,前提是要查找的表达式是静态的(不幸的是,我的不是)。正则表达式需要更多的工作,比如 this.
如果有帮助,表达式将锚定在行首,例如:"^foo \d+$"
.
无论您编写什么脚本,几乎肯定会比以下脚本慢:
tac file | grep -m 1 '^foo [0-9][0-9]*$'
此 awk
脚本将搜索整个文件并打印匹配给定 /pattern/
:
$ awk '/pattern/ { line=[=10=] } END { print $line }' gigantic.log
使用 tac
将是一个更好的选择(这使用 GNU sed
输出第一个(即最后一个)找到的匹配 '/pattern/',之后它终止,终止管道):
$ tac gigantic.log | gsed -n '/pattern/{p;q}'
使用 Perl 或 C 或其他语言,您可以查找到文件末尾,后退 4kb(或其他),然后
- 向前读4kb,
- 后退8kb
- 重复直到找到模式,确保正确处理读取部分行。
(这个,除了寻找模式,实际上可能是 tac
所做的:one implementation of tac
)