12

How i can read a certain number of lines after find some text?

Eg.:

Read next 2 lines after find "Unix" on:

Test 1
Test 2
Test 3
Test 4
UNIX
Test 5
Test 6
Test 7
Test 8
Test 9

Result can be:

Test 5
Test 6

Note: The "Unix" on last example is an argument, and so, it can be any other text.

What i have:

I'm still out of ideas, need just a light. Thinking on create another script to do that.

10

An awk solution:

$ awk '$0 == "UNIX" {i=1;next};i && i++ <= 2' file
Test 5
Test 6

Explanation

  • /^UNIX$/{i=1;next}: if we see UNIX, we set variable i = 1, processing to next input.

  • If variable i is set (meaning we saw UNIX), i && i++ <= 2 only evaluated to true value in next two lines after UNIX, causing awk performed default action print $0.

  • Before seeing UNIX, i was not defined and begin at 3rd line after UNIX, i had a value greater than 2, which make expression i && i++ <= 2 evaluated to false, causing awk do nothing.

  • After test you solution im getting this error message: error systax near line 1 bailing out near line 1 – Cold Oct 15 '14 at 14:53
  • @Cold: What did you run? Please note that the $ sign at beginning of my answer is shell prompt, not part of awk command. – cuonglm Oct 15 '14 at 14:58
  • Another variant: awk '/^UNIX$/ {s=NR;next} s && NR<=s+2' – musiphil Oct 15 '14 at 17:41
  • I know that @cuonglm – Cold Oct 15 '14 at 17:58
  • @Cold: What is your OS? – cuonglm Oct 15 '14 at 18:33
12

A grep solution:

grep -A2 -P '^UNIX$' file

Explanation: -A means: print the next two lines after the match

Or awk:

awk '$0=="UNIX"{getline; print; getline; print}' file

Explanation: That statement searches for UNIX in the line ($0=="UNIX"). If that is given it gets the next next into its buffer (getline) and prints the buffer (print). This is done twice.

Or use sed:

sed -n '/^UNIX$/{n;p;n;p}' file

Explanation: That seaches for UNIX (/^UNIX$/). If this is found it txecutes the part in the {...}. n means next, p means print. This is done twice as well.

  • Thanks @chaos, i will trys the last 2 option that you give. PLease append some explanation of each option, i wonna compreend and do. – Cold Oct 15 '14 at 14:49
  • If the number of lines changes, how many changes i will make on last two options? Thanks – Cold Oct 15 '14 at 14:51
  • @Cold see my edit. To change the number if lines repeat the getline; print; part in the awk statement or the n;p; part in the sed statement. – chaos Oct 15 '14 at 14:57
  • Thanks @chaos, but the higher the number of lines is increased expression and the change is not feasible in my opinion. Do not you think? If 100 lines? – Cold Oct 15 '14 at 15:00
  • @Cold Then I would use the grep solution with grep -A100 -P '^UNIX$' file | tail -n +2. The tail part is to remove the first lien. In the others (sed, awk) you would have to write loops, what makes it less simple. – chaos Oct 15 '14 at 17:01
4
grep -A 2 UNIX file.txt

The manpage of grep describes the option thus:

  -A NUM, --after-context=NUM
      Print NUM  lines  of  trailing  context  after  matching  lines.
      Places  a  line  containing  --  between  contiguous  groups  of
      matches.
  • Hi @Twinkles, good answer, but my grep has only this options "hblcnsviw". But the logics is good. thanks – Cold Oct 15 '14 at 14:48
  • This will print UNIX in output, too. – cuonglm Oct 15 '14 at 15:00
  • To omit the UNIX, pipe it to tail: [...] | tail -n +1, or to sed: [...] | sed '1d'. – DopeGhoti Oct 15 '14 at 20:32
  • 1
    @DopeGhoti: your tail and sed '1d' suggestions work correctly only if UNIX appears only once in the input text. All the other answers allow for multiple occurrences. It might be better to suggest ... | grep -v UNIX. Admittedly, this gets messy if UNIX appears on lines 15 and 17. – G-Man Says 'Reinstate Monica' Oct 15 '14 at 21:36
  • Good points. I'm pretty sure it could just be done in sed with some form of sed '/UNIX/d;n;n;p/' /path/to/file, which I just sussed out and submitted as an answer. – DopeGhoti Oct 15 '14 at 21:38
0

This seems to do the trick nicely:

sed -n '/UNIX/{n;p;n;p}' /path/to/file

Proof of concept:

$ for i in {1..9}; do echo $i; done | sed -n '/4/{n;p;n;p}'
5
6
  • 1
    The subshell around your for loop isn't necessary. – Paused until further notice. Oct 15 '14 at 21:58
  • Indeed it is not; it was a remnant of some other faffery I was in the midst of on that shell earlier in the day. Parens removed. – DopeGhoti Oct 16 '14 at 6:44
0

You can use ex:

ex -s +'1,/UNIX/d|%p|q!' file_or_/dev/stdin

where:

  • 1,/UNIX/d - removes text after match
  • %p - prints buffer
  • q! - quit without saving changes to file (use wq to edit in-place)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.