Grep以相反顺序而不读取整个文件

时间:2016-07-17 12:28:00

标签: grep posix reverse large-files

我有一个非常大的日志文件(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并不强大。)
  • &#34;没有加速,所以为什么要打扰&#34;:我认为这是不正确的,因为文件系统可以在不读取整个文件的情况下寻找文件的末尾。为了找到每一个新行,有一点试验和错误/缓冲,但与读取(例如)从未使用的10 GB相比,这不应该减慢很多。
  • 编写一个python / perl脚本来执行此操作:如果没有人可以提出更好的建议,这就是我的后退。我宁愿坚持通过命令行直接完成的事情,因为我直接通过ssh执行它,而且我也不必上传脚本文件。在python中使用mmap的rfind(),我认为我们可以在几行中完成它,前提是find的表达式是静态的(不幸的是,我的不是)。正则表达式需要更多的工作,例如this

如果有帮助,表达式将锚定在一行的开头,例如:"^foo \d+$"

2 个答案:

答案 0 :(得分:3)

你编写的任何脚本几乎肯定会慢于:

tac file | grep -m 1 '^foo [0-9][0-9]*$'

答案 1 :(得分:0)

awk脚本将搜索整个文件并打印与给定/pattern/匹配的最后一行:

$ awk '/pattern/ { line=$0 } 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