Reputation: 2999
Suppose I have:
content line 1
content line 2
blabla *my_pattern_str* (1st occurrence)
...
content line x
blabla *my_pattern_str* (nth occurrence <- I want to print from the beginning line up to here)
content line y
content line y+1
...
I would like to print all the lines before and including the nth occurrence of my_pattern_str. How can I do this using sed
(or similar command like grep
or awk
)?
Upvotes: 3
Views: 2885
Reputation: 1118
This is horrible, but it does exactly what you asked for.
cat input_file.txt \
| tr '\n' '\0' \
| sed -e 's:my_pattern:my_pattern\
:g' \
| head -n$X \
| tr -d '\n' \
| tr '\0' '\n'
Notice the awesome use of an escaped newline within the sed pattern - I'm not sure if this can be avoided.
The idea here is to:
\0
head -n X
to grab the first X
matches\0
characters with newlinesUpvotes: 1
Reputation: 241671
Adjust 7
and my_pattern
as necessary.
awk -v N=7 '{print}/my_pattern/&&--N<=0{exit}'
More cryptically, the following will also work:
awk -v N=7 '1;/my_pattern/&&--N<=0{exit}'
Both of the above actually stop on the Nth line containing the pattern, rather than the Nth occurrence of the pattern. If you want the Nth occurrence of the pattern:
awk -v N=7 -v M=my_pattern '1;(N-=gsub(M,""))<=0{exit}'
Eg:
printf %s\\n line1 "pattern in line 2" "pattern pattern in line 3" line4 pattern |
awk -v N=3 -v M=pattern '1;(N-=gsub(M,""))<=0{exit}'
=>
line1
pattern in line 2
pattern pattern in line 3
Upvotes: 2
Reputation: 74596
You could use this. The variable N
is the max number of times. It will process the rest of the file but I don't think that's a big deal:
awk -vN=2 'n<N;/my_pattern/{++n}' file
Increment a counter every time the pattern is matched. Print the line as long as the counter is lower than the the variable N
.
Upvotes: 7
Reputation: 75458
This would only print those lines if a pattern really exists along the way and not print everything if it's not found:
awk '{lines[NR]=$0}/pattern/{for(i=1;i<=NR;++i)print lines[i];exit}' file
Upvotes: 0