LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 10-26-2011, 03:11 PM   #1
cristalp
Member
 
Registered: Aug 2011
Distribution: Linux Mint
Posts: 103

Rep: Reputation: Disabled
print nth line after the line which matches the string


Dear Experts,

I have a file which looks like:
Code:
111111
222222
33aaa3
444444
555555
666666
777777
...
What I want is to print the third line (which should be 666666) after the line where aaa was found. I mean, I need to first search through the file to find a line includes string "aaa", then print out the third (or nth) line 666666 after this line.

I tired:
Code:
awk '{a[NR] = $0} $0 ~ /aaa/ {printf("%s\n", a[NR+3])}' FILENAME
This gave me empty output. But if I try for example:
Code:
awk '{a[NR] = $0} $0 ~ /aaa/ {printf("%s\n", a[NR-1])}' FILENAME
With this command, I can get the line 222222 which is above the line with aaa. (exactly NR-1).

So, why I can not do this same way for line after(NR+n)? How could I achieve my goal, with awk or grep(I am not that in sed)?

Any reply would be greatly appreciated. Thank you very much!

Last edited by cristalp; 10-26-2011 at 03:13 PM.
 
Old 10-26-2011, 03:51 PM   #2
druuna
LQ Veteran
 
Registered: Sep 2003
Posts: 10,532
Blog Entries: 7

Rep: Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374
Hi,

Try this:
Code:
grep -A3 "aaa" infile | tail -1
Hope this helps.
 
Old 10-27-2011, 01:28 AM   #3
grail
Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 7,627

Rep: Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947
The issue with your awks is you can see in the past (ie what you have stored in the array), but you cannot see into the future (ie NR +3 has yet to be stored).

What you would try and do if you use awk is:
Code:
awk '/aaa/{x = NR + 3}NR == x' file
 
Old 10-27-2011, 02:37 AM   #4
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942
I'm with grail, except that if you have multiple matches per file, I'd use an indicator array:
Code:
awk '/aaa/ { show[NR+3] = 1 } (NR in show) { print $0 ; delete show[NR] }' infile
The delete will trim the array, so it'll ever only contain the to-be-printed record numbers. It's a good idea if you happen to process files with many occurrences, but basically it's just an optimization.

If you have multiple trigger patterns, you could even do
Code:
awk '/aaa/ { show[NR+3] = "aaa" }
     /bbb/ { show[NR+3] = "bbb" }
     (NR in show) { printf("%s: %s\n", show[NR], $0) ; delete show[NR] }
    ' infile
although in this simple form it wont tell you if a line was printed for more than one trigger. To list all reasons, you'd need to use for example
Code:
awk '/aaa/ { if ((NR+3) in show) show[NR+3] = show[NR+3] ", aaa" ; else show[NR+3] = "aaa" }
     /bbb/ { if ((NR+3) in show) show[NR+3] = show[NR+3] ", bbb" ; else show[NR+3] = "bbb" }
     (NR in show) { printf("%s: %s\n", show[NR], $0) ; delete show[NR] }
    ' infile
 
Old 10-27-2011, 03:34 AM   #5
expertshell
LQ Newbie
 
Registered: Oct 2011
Location: BeiJing China
Distribution: Fedora
Posts: 3

Rep: Reputation: Disabled
grail's is a good solution
 
0 members found this post helpful.
Old 10-27-2011, 08:00 AM   #6
grail
Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 7,627

Rep: Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947
Yes but where mine gets caught is if the pattern appears more than once prior to the line required:
Code:
111111
222222
33aaa3
44aaa4
555555
666666
777777
Here you should get the 6s and the 7s but mine will only print the last entry. A slight alteration you can make to NA's is:
Code:
awk '/aaa/ { show[NR+3]++  } show[NR]' file
 
Old 10-27-2011, 02:19 PM   #7
cristalp
Member
 
Registered: Aug 2011
Distribution: Linux Mint
Posts: 103

Original Poster
Rep: Reputation: Disabled
Thanks everyone!

Thanks everyone! Your kind and excellent answers expand this small question to a big tank of knowledge and skills. I am glad to see that we share our knowledge so broadly. This is why I join this forum and I hope every one got her progress through the communication.

I, myself, also found another way to solve this problem from a similar problem in another forum:
Code:
grep -A 3 aaa FILENAME | sed -n '4~5p'
Anybody know the meaning of '4~5p'?

Let's keep this question unsolved for a bit while, since I still have some questions on your replies. I will put my questions later on. Please wait for a bit...
 
Old 10-27-2011, 02:53 PM   #8
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950
First of all, useless use of grep, since sed can also match text.

Second, did you look in the sed man page? It explains what that pattern means.

But I'd use A1,+N instead, since you want a fixed number of lines after the match, rather than a step.

So use one address range to grab that section of lines, then apply a second nested command to it to print just the line you want.

Code:
sed -n '/aaa/,+3 { 1,+2d ; p }' file.txt
I don't know why, but the nested address matching is kind of tricky. I can't get it to just directly print the last line of the initial match ($ still seems to mean the last line of the file), so you have to tell it to delete everything before it instead.
 
  


Reply

Tags
awk


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] AWK print line only if next line matches a string wolverene13 Linux - Newbie 8 10-03-2011 04:32 PM
need to delete a line if a field of that line matches using awf in bash scripting accesskarthi Linux - Newbie 8 06-29-2009 04:15 AM
C++ text file line by line/each line to string/array Dimitris Programming 15 03-11-2008 09:22 AM
Regex Question: Only print part of line that matches TheMeteorPolice Programming 5 01-12-2006 02:21 PM


All times are GMT -5. The time now is 10:53 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration