grep -A1 'blah' logfile
Thanks to this command for every line that has 'blah' in it, I get the output of the line that contains 'blah' and the next line that follows in the logfile. It might be a simple one but I can't find a way to omit the line that has 'blah' and only show next line in the output.
-A1
option
curl whatismyip.org | grep -A1 'Your IP Address'
-A1
. Thanks!
you can try with awk:
awk '/blah/{getline; print}' logfile
If you want to stick to grep:
grep -A1 'blah' logfile | grep -v "blah"
or alternatively with sed:
sed -n '/blah/{n;p;}' logfile
Piping is your friend...
Use grep -A1
to show the next line after a match, then pipe the result to tail
and only grab 1 line,
cat logs/info.log | grep "term" -A1 | tail -n 1
Great answer from raim, was very useful for me. It is trivial to extend this to print e.g. line 7 after the pattern
awk -v lines=7 '/blah/ {for(i=lines;i;--i)getline; print $0 }' logfile
Many good answers have been given to this question so far, but I still miss one with awk
not using getline
. Since, in general, it is not necessary to use getline
, I would go for:
awk ' f && NR==f+1; /blah/ {f=NR}' file #all matches after "blah"
or
awk '/blah/ {f=NR} f && NR==f+1' file #matches after "blah" not being also "blah"
The logic always consists in storing the line where "blah" is found and then printing those lines that are one line after.
Test
Sample file:
$ cat a
0
blah1
1
2
3
blah2
4
5
6
blah3
blah4
7
Get all the lines after "blah". This prints another "blah" if it appears after the first one.
$ awk 'f&&NR==f+1; /blah/ {f=NR}' a
1
4
blah4
7
Get all the lines after "blah" if they do not contain "blah" themselves.
$ awk '/blah/ {f=NR} f && NR==f+1' a
1
4
7
If that next lines never contain 'blah', you can filter them with:
grep -A1 blah logfile | grep -v blah
The use of cat logfile | ...
is not needed.
<logfile grep -A1 blah | grep -v blah
It is perfectly valid BASH!
In general, I agree you're asking a lot of grep here, and that another tool may be the better solution. But in an embedded environment, I may not want to have sed
or awk
just to do this. I found the following solution works (as long as they're not contiguous matches):
grep -A1 AT\+CSQ wvdial.out | grep -v AT\+CSQ
Basically, match them, appending 1 line of context for each match, and then pipe that through an inverse match of your original pattern to strip those out. This of course means you can assume that your pattern doesn't show up in the "next" line.
I don't know of any way to do this with grep, but it is possible to use awk to achieve the same result:
awk '/blah/ {getline;print}' < logfile
perl one-liner alert
just for fun... print only one line after match
perl -lne '$. == $next && print; $next = ($.+1) if /match/' data.txt
even more fun... print the next ten lines after match
perl -lne 'push @nexts, (($.+1)..($.+10)) if /match/; $. ~~ @nexts && print' data.txt
kinda cheating though since there's actually two commands
$. == $next && print
is the same as print if $. == $next
grep -A1
). If you want to print only next lines but never a line with a match, then you would keep it this order. (just noting how $next would be clobbered for consecutive matches)
It looks like you're using the wrong tool there. Grep isn't that sophisticated, I think you want to step up to awk as the tool for the job:
awk '/blah/ { getline; print $0 }' logfile
If you get any problems let me know, I think its well worth learning a bit of awk, its a great tool :)
p.s. This example doesn't win a 'useless use of cat award' ;) http://porkmail.org/era/unix/award.html
you can use grep, then take lines in jumps:
grep -A1 'blah' logfile | awk 'NR%3==2'
you can also take n lines after match, for example:
seq 100 | grep -A3 .2 | awk 'NR%5==4'
15
25
35
45
55
65
75
85
95
explanation -
here we want to grep all lines that are *2 and take 3 lines after it, which is *5.
seq 100 | grep -A3 .2
will give you:
12
13
14
15
--
22
23
24
25
--
...
the number in the modulo (NR%5) is the added rows by grep (here it's 3 by the flag -A3), +2 extra lines because you have current matching line and also the -- line that the grep is adding.
grep /Pattern/ | tail -n 2 | head -n 1
Tail first 2 and then head last one to get exactly first line after match.
You can match multiple lines and output n lines after with:
awk 'c&&!--c;/match1/{c=1};/match2/{c=2}' file
Match multiple items and output n lines after:
#!/bin/sh
[ -z $3 ] && echo $0 file \[match n\]+... \# to output line n after match && exit
f=$1; shift; while [ \! -z $2 ]; do s="$s/$1/{c=$2};"; shift; shift; done
awk 'c&&!--c;'$s $f
So you can save the above as matchn.sh
and chmod +x matchn.sh
and then if you have a file like this:
line1
line2
line3
line4
line5
line6
line7
And run:
./matchn.sh file line1 1 line3 2 line6 1
You will get:
line2
line5
line7
This will need a bit more tweaking to support 0 offsets.
Success story sharing
awk '/blah/{getline; getline; print}' logfile