Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grep in reverse order without reading whole file

I have a log file that may be very large (10+ GB). I'd like to find the last occurrence of an expression. Is it possible to do this with standard posix commands?

Here are some potential answers, from similar questions, that aren't quite suitable.

  • Use tail -n <x> <file> | grep -m 1 <expression>: I don't know how far back the expression is, so I don't know what <x> would be. It could be several GB previous, so then you'd be tailing the entire file. I suppose you could loop and increment <x> until it's found, but then you'd be repeatedly reading the last part of the file.
  • Use tac <file> | grep -m 1 <expression>: tac reads the entire source file. It might be possible to chain something on to sigkill tac as soon as some output is found? Would that be efficient?
  • Use awk/sed: I'm fairly sure these both always start from the top of the file (although I may be wrong, my sed-fu is not strong).
  • "There'd be no speed up so why bother": I think that's incorrect, since file systems can seek to the end of a file without reading the whole thing. There'd be a little trial and error/buffering to find each new line, but that shouldn't slow things down much, compared to reading (e.g.) 10 GB that are never used.
  • Write a python/perl script to do it: this is my fall-back if no one can suggest anything better. I'd rather stick to something that can be done straight through the command line, since I'm executing it straight through ssh, and I'd rather not have to upload a script file as well. Using mmap's rfind() in python, I think we can do it in a few lines, provided the expression to find is static (which mine, unfortunately, is not). A regex requires a bit more work, something like this.

If it helps, the expression is anchored at the start of a line, eg: "^foo \d+$".

like image 329
Amanda Ellaway Avatar asked Jul 17 '16 12:07

Amanda Ellaway


People also ask

How do you reverse grep output?

Inverting Grep Expression In order to invert a grep expression, we just need to make use of the -v flag along with the grep command.

How do you grep silently?

The quiet option ( -q ), causes grep to run silently and not generate any output. Instead, it runs the command and returns an exit status based on success or failure. The return status is 0 for success and nonzero for failure.

How do you make grep negative?

To use negative matching in grep , you should execute the command with the -v or --invert-match flags. This will print only the lines that don't match the pattern given.

How do you grep 5 lines before and after?

For BSD or GNU grep you can use -B num to set how many lines before the match and -A num for the number of lines after the match. If you want the same number of lines before and after you can use -C num . This will show 3 lines before and 3 lines after.


1 Answers

Whatever script you write will almost certainly be slower than:

tac file | grep -m 1 '^foo [0-9][0-9]*$'
like image 162
Ed Morton Avatar answered Oct 18 '22 02:10

Ed Morton