2

How can I view in less from the first instance of some arbitrary string "foo" to the last instance?

This arbitrary string will be on most every line of the log. I don't want to do grep "foo" bar.log | less because it won't be on each line that's relevant.

Let's say the file is

1 Random junk I don't want to see
2 Care about (foo)
3 Care about (foo)
4 Care about
5 Care about (foo)
6 Other random junk I don't want to see

Unfortunately the lines I want to ignore do not follow a nice pattern, otherwise I could use just grep -v 'insert pattern here'.

I am wondering how to get the following into less somehow,

2 Care about (foo)
3 Care about (foo)
4 Care about
5 Care about (foo)

grep "foo" bar.log | less will not work because it ignores line 4, which is one I care about.

Captain Man
  • 1,186

3 Answers3

4

If you have awk you can do:

awk '/foo/{print b$0;b="";x=1;next} x{b=b$0"\n"}' bar.log | less

When a foo appears, it prints buffer (b variable) and current line, and clears the buffer.

Otherwise, but only if foo already appeared (x variable) it buffers current line.

mik
  • 1,342
1

It takes some careful shell quoting, but you could use the scriptable editor ed for this:

printf '%s\n' "/foo/ka" "??" "'a,.w "'!less' q | ed -s file

This sends four commands to ed:

  1. /foo/ka -- searches (from the beginning of the file) for the pattern foo; at that first match, set a mark named a.
  2. ?? -- repeat the search, but going backwards, wrapping around the end of the file; the important byproduct here is that it sets the current line to that (last) match.
  3. 'a,.w !less -- from the mark named a through the current line (.), write those lines to the shell command (!) less.
  4. q -- quit ed.

You'll need to exit less gracefully (q) in order for ed to exit. This solution assumes that the pattern exists at least once in the file, otherwise the searches will fail and you'll get three ?'s before ed exits.

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
0

Are you looking to use grep to exclude matching lines, rather than include them? If so, try: grep -v "Don't care about"

izzy
  • 101
  • Unfortunately not all the lines I want to skip have a nice pattern. I made them all say that in the question to make it a little more clear what I asking for. In reality this is about getting the "subsection" of the logs for a specific transaction. Many (but not all) of the lines relevant have the transaction's ID. Some log messages span multiple lines. That's why I wanted to get everything between the first and last instead of just reversing the filter. I will update the question to make this more obvious. – Captain Man Oct 29 '19 at 18:50