Print line after nth occurrence of a match

18,578

Solution 1

awk -v n=3 '/<Car>/ && !--n {getline; print; exit}'

Or:

awk '/<Car>/ && ++n == 3 {getline; print; exit}'

To pass the search pattern as a variable:

var='<car>'
PATTERN="$var" awk -v n=3 '
  $0 ~ ENVIRON["PATTERN"] && ++n == 3 {getline; print; exit}'

Here using ENVIRON instead of -v as -v expands backslash-escape sequences and backslashes are often found in regular expressions (so would need to be doubled with -v).

GNU awk 4.2 or above lets you assign variables as strong typed regexps. As long as its POSIX mode is not enabled (for instance via the $POSIXLY_CORRECT environment variable, you can do:

# GNU awk 4.2 or above only, when not in POSIX mode
gawk -v n=3 -v pattern="@/$var/" '
  $0 ~ pattern && ++n == 3 {getline; print; exit}'

Solution 2

Here's a perl one:

perl -ne 'print && exit if $c==3; $c++ if /<Car>/;' file 

With GNU grep, you can also parse its output like:

grep -A 1 -m 3 '<Car>' file | tail -n 1

From man grep:

-A NUM, --after-context=NUM
          Print NUM lines of trailing context after matching lines.  
          Places a line containing a group separator (--) between 
          contiguous  groups  of  matches.          
-m NUM, --max-count=NUM
          Stop reading a file after NUM matching lines.  

Solution 3

With GNU awk you can do:

gawk -v RS='</Car>' 'NR==3 && $0=$2' inputFile

Solution 4

Here's another way with sed:

sed -n '/<Car>/{x;/.\{2\}/{x;$!{n;p};q};s/.*/&./;x}' infile

This is using the hold space to count.
Each time it encounters a line matching <Car> it exchanges buffers and checks if there are exactly N-1 occurrences of a character in the hold buffer. If the check is successful it exchanges again, and if not on the last line, it pulls in the next line and prints the pattern space then quits. Otherwise it just adds another . char to the hold space and exchanges back.

Share:
18,578

Related videos on Youtube

DJ180
Author by

DJ180

Updated on September 18, 2022

Comments

  • DJ180
    DJ180 over 1 year

    I am looking to display the line 4598 in the following file. Effectively I want to display the line AFTER the nth occurrence of a match. In this case, the line after the 3rd occurrence of <Car>. How do I go about this?

    <Car>
    10456
    </Car>
    <Car>
    70192
    </Car>
    <Car>
    4598
    </Car>
    
    • devnull
      devnull about 10 years
      While it might be possible to achieve what you want using sed, awk, or even grep, it's advisable to make use of a XML parser.
    • DJ180
      DJ180 about 10 years
      XML was only used for the example, text may be any format
  • rambalachandran
    rambalachandran almost 8 years
    How to pass the search pattern also as a variable in the above command
  • Stéphane Chazelas
    Stéphane Chazelas almost 8 years
    @WanderingMind, see edit.