7

I want to extract the Nth line after a matching pattern using grep, awk or sed.

For example I have this piece of text:

      Revision:
      60000<br />

And I want to extract 60000.

I tried Revision:([a-z0-9]*)\s*([0-9]){5} which matches the Revision together with the revision number but when I pass it to grep: grep Revision:([a-z0-9]*)\s*([0-9]){5} file.html I get nothing.

How can I achieve this?

nhahtdh
  • 55,989
  • 15
  • 126
  • 162
Jacob Krieg
  • 2,834
  • 15
  • 68
  • 140

3 Answers3

31

To extract the Nth line after a matching pattern you want:

awk 'c&&!--c;/pattern/{c=N}' file

e.g.

awk 'c&&!--c;/Revision:/{c=5}' file

would print the 5th line after the text "Revision:"/.

See Printing with sed or awk a line following a matching pattern for more information.

Ed Morton
  • 188,023
  • 17
  • 78
  • 185
  • 3
    `c&&!--c` is equivalent to `c!=0 && --c==0` and `c&&c--` is equivalent to `c!=0 && --c>=0`; the alternatives may be easier to understand. – musiphil Jan 16 '14 at 23:43
  • 1
    One caveat is that if a pattern appears again before reaching the next N'th line, the counter is reset and the earlier appearances are forgotten. For example, in c), if N=10 and the pattern is in lines 21 and 28, then only line 38 will be printed but not line 31. To deal with this, you can use `awk '/pattern/{p[NR+N]=1} NR in p'` (simpler) or `awk '/pattern/{p[NR+N]=1} NR in p{print; delete p[NR]}'` (keeps the memory usage bounded). – musiphil Jan 16 '14 at 23:54
  • How to modify f.) to not to print the line with pattern (it is doing so now)? – Betlista Aug 11 '16 at 12:29
  • As answered here - http://stackoverflow.com/questions/38895234/combine-v-option-for-grep-with-a-option the modification is `awk '/abc/ {c=0} c++>4' file` – Betlista Aug 11 '16 at 12:56
  • @Betlista No, you just swap the parts that recognize the condition and skip lines to get the rearranged `awk '/pattern/{c=N} c&&c--{next} 1' file`. What you wrote, `awk '/abc/ {c=0} c++>4' file`, does something quite different, e.g. it'll unconditionally skip the first 5 lines of input. – Ed Morton Aug 11 '16 at 13:32
6

Printing the lnbth line after first blank/empty line:

Index of line to print (in bash shell):

lnb=2
  • Using sed:

    sed -ne '/^\s*$/{:a;n;0~'"$lnb"'!ba;p;q}' my_file`
    
  • Using perl:

    perl -ne '/^\s+$/ && $k++;$k!=0 && $k++ && $k=='"$lnb"'+2 && (print,last)' my_file`
    

Printing the lnbth line after regular-expression match:

  • Using sed:

    sed -ne '/regex/{:a;n;0~'"$lnb"'!ba;p;q}' my_file
    
  • Using perl:

    perl -ne '/regex/ && $k++;$k!=0 && $k++ && $k=='"$lnb"'+2 && (print,last)' my_file
    

    Bonus 1, Windows PowerShell (install Perl first) :

    $lnb=2
    
    perl -ne "/regex/ && `$k++;`$k!=0 && `$k++ && `$k==$lnb+2 && (print,last)" my_file
    

    Bonus 2, Windows DOS command line :

    set lnb=2
    
    perl -ne "/regex/ && $k++;$k!=0 && $k++ && $k==%lnb%+2 && (print,last)" my_file
    

Printing ALL lnbth lines after regular-expression match:

  • Using perl(bash example):

    perl -ne '/regex/ && $k++;$k!=0 && $k++ && $k=='"$lnb"'+2 && (print,$k=0)' my_file
    
lerems04
  • 61
  • 1
  • 2
1

I like solutions I can learn to redo, without having to google for it every time. This solution is not perfect, but uses simple grep commands that I can write from memory.

grep -A7 "searchpattern" file | grep -B1 "^--$" | grep -v "^--$"

You can change the 7 to the nth line you want after the search pattern. It then searches for the "group separator" -- and shows the last line before that. Then remove the group separators.

The only case this does not work correctly is if your data contains lines with only "--".

Veda
  • 2,025
  • 1
  • 18
  • 34