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 |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
|
 |
10-26-2011, 02:11 PM
|
#1
|
Member
Registered: Aug 2011
Distribution: Linux Mint
Posts: 103
Rep: 
|
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 02:13 PM.
|
|
|
10-26-2011, 02:51 PM
|
#2
|
LQ Veteran
Registered: Sep 2003
Posts: 10,532
|
Hi,
Try this:
Code:
grep -A3 "aaa" infile | tail -1
Hope this helps.
|
|
|
10-27-2011, 12:28 AM
|
#3
|
LQ Guru
Registered: Sep 2009
Location: Perth
Distribution: Arch
Posts: 10,038
|
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
|
|
|
10-27-2011, 01:37 AM
|
#4
|
Senior Member
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
|
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
|
|
|
10-27-2011, 02:34 AM
|
#5
|
LQ Newbie
Registered: Oct 2011
Location: BeiJing China
Distribution: Fedora
Posts: 3
Rep: 
|
grail's is a good solution
|
|
0 members found this post helpful.
|
10-27-2011, 07:00 AM
|
#6
|
LQ Guru
Registered: Sep 2009
Location: Perth
Distribution: Arch
Posts: 10,038
|
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
|
|
|
10-27-2011, 01:19 PM
|
#7
|
Member
Registered: Aug 2011
Distribution: Linux Mint
Posts: 103
Original Poster
Rep: 
|
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...
|
|
|
10-27-2011, 01:53 PM
|
#8
|
Bash Guru
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852
|
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.
|
|
|
All times are GMT -5. The time now is 04:17 PM.
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|