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.
3 Answers 3
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.
-
Both this and @Stephane 's solution work. How do these stop on the last
foo
?Captain Man– Captain Man2016年03月17日 16:36:33 +00:00Commented Mar 17, 2016 at 16:36 -
1@CaptainMan only when
foo
appears, the lines since lastfoo
are printed.mik– mik2016年03月17日 16:43:27 +00:00Commented Mar 17, 2016 at 16:43
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
:
/foo/ka
-- searches (from the beginning of the file) for the pattern foo; at that first match, set a mark nameda
.??
-- 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.'a,.w !less
-- from the mark nameda
through the current line (.
), write those lines to the shell command (!
)less
.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.
Are you looking to use grep to exclude matching lines, rather than include them? If so, try: grep -v "Don't care about"
-
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– Captain Man2019年10月29日 18:50:40 +00:00Commented Oct 29, 2019 at 18:50
sed
beforeless
?grep
, one where you only get shown one result at a time and you can switch between them?grep
andsed
because they seemed like the tools that would be able to do this.pcregrep -M 'foo.*(\n|.)*foo' infile