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.

asked Mar 17, 2016 at 15:01
6
  • you say "don't want to grep" but you tagged sed and grep; are you opposed to calling sed before less? Commented Mar 17, 2016 at 15:23
  • So you want an interactive grep, one where you only get shown one result at a time and you can switch between them? Commented Mar 17, 2016 at 15:28
  • @Jeff I don't mind at all, I just tagged with grep and sed because they seemed like the tools that would be able to do this. Commented Mar 17, 2016 at 15:31
  • This has been asked before more than once - here's just an example: How can I "grep" patterns across multiple lines? so in your case pcregrep -M 'foo.*(\n|.)*foo' infile Commented Mar 17, 2016 at 15:32
  • @phk no, that's not what I meant, I've updated with an example. Commented Mar 17, 2016 at 15:33

3 Answers 3

4

If you have awk you can do:

awk '/foo/{print b0ドル;b="";x=1;next} x{b=b0ドル"\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.

answered Mar 17, 2016 at 16:19
2
  • Both this and @Stephane 's solution work. How do these stop on the last foo? Commented Mar 17, 2016 at 16:36
  • 1
    @CaptainMan only when foo appears, the lines since last foo are printed. Commented Mar 17, 2016 at 16:43
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.

answered Oct 29, 2019 at 19:11
0

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

answered Oct 29, 2019 at 18:35
1
  • 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. Commented Oct 29, 2019 at 18:50

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.