1

Is it possible to scan a file for a pattern in reverse (bottom up) using ack (the grep alternative)?

Right now I am using:

tac filename | grep -m1 blablabla

but a friend mentioned that ack might be able to do this type of thing without the use of tac. I went through the man file and could not find anything mentioning this capability (or maybe I was just dumb and missed it).

If it is not possible to do the above, what would be a more efficient way of doing this type of search? (find the first match of a pattern starting at the bottom of a file)

lacrosse1991
  • 2,972
  • 7
  • 38
  • 47
  • there can be multiple options. but don't know which is most efficient. e.g., for simple patterns, awk can work too: `awk '/blabla/{a=$0};END{print a}' filename` Advantage over `tac|grep` is that `tac` can take large system memory for larger files. – anishsane Apr 23 '15 at 04:17
  • No, ack cannot read through files backwards. – Andy Lester Jun 10 '15 at 19:27

2 Answers2

1

Reading a file in such a reverse line-oriented fashion is always going to be inefficient, due to how files are stored on disk. A file is simply a linear stream of bytes, accessible by an offset from the beginning the file. A line is not a distinct object; rather, it's a abstraction defined by a conventional byte (or pair of bytes) know as the line ending. The first line is everything from the beginning of the file up to the first line ending, the second line is everything after the first line ending up to the second line ending, and so on. In order to access the lines in reverse, you still need to scan the entire file from the beginning to even find the last line.

The command line you have is probably as good as you can do. I'm not aware of any option to ack that will do the reverse line-iteration for you, but even if it did, it would be only marginally more efficient than letting a dedicated program like tac handle it (the difference coming from doing the file I/O itself, rather than having the overhead of a second process and setting up the interprocess communication of a pipe).

chepner
  • 497,756
  • 71
  • 530
  • 681
  • 1
    To be fair using c/c++ and scanning to the end of even giant files takes negligible amount of time. –  Apr 23 '15 at 09:59
  • True, but actually reading the lines in reverse order introduces the complication of having to re-read blocks from disk (picture a line that begins in one disk block and ends in the next) or do in-app caching to save partial lines before reading the previous block in the file. This also introduces the possibility of more cache misses. – chepner Apr 23 '15 at 13:26
  • I don't know what you mean, you would just take a chunk and stick it in memory, then go through that, and then get the next chunk where that one had ended.The only reason you would run into trouble would be if you were using something like getline which requires complete lines. –  Apr 23 '15 at 13:32
  • Thanks, in this case I will probably stick with tac. I am using this to find the last occurrence of a certain string in a log file. – lacrosse1991 Apr 25 '15 at 18:14
1

This is only useful if you're working interactively, but most (the pager) has a reverse search functionality which can be very fast for getting the last entry in a large file. Usage:

  1. most my_big_file
  2. press B to skip to the end of the file
  3. press shift-/ to engage search in backwards mode, and search for what you want - it'll return the last entry in the file, without the slowness of buffering the entire thing as with tac.

Unfortunately I'm not currently aware of a non-interactive solution.

Riot
  • 15,723
  • 4
  • 60
  • 67
  • I've not used the B key in most before (though most is my go to text file reader), will have to remember this for the future, thanks! – lacrosse1991 Apr 25 '15 at 18:13