Using Raku (formerly known as Perl_6)
raku -ne 'state $i=0; .put if m/ P1 {last if $i++ == 1} /fff/ P2 /;'
#OR
raku -e 'my $i=0; .put if m/ P1 {last if $i++ == 1} /fff/ P2 / for lines;'
#OR
raku -e 'my $i=0; for lines() { .put if m/ P1 {last if $i++ == 1} /fff/ P2 / };'
Sample Input:
text
something P1 something
content1
content2
something P2 something
text
something P1 something
content3
content4
something P2 something
text
Sample Output (1):
something P1 something
content1
content2
something P2 something
The above answer is coded in Raku, a member of the Perl-family of programming languages. Explaining the first answer briefly, Raku's non-autoprinting -ne
command line flags are employed to run code over each line of input. Raku's m/<start>/fff/<stop>/
sed-like "flip-flop" operator is employed which takes linewise input (special-cased within the Rakudo compiler), enabling the return of text blocks that start with the first matching line and stop with the second matching line. The variable $i
is state
d once at the beginning of the loop to equal 0
zero. Finally, Raku also allows code blocks to execute within Regexes upon matching.
Putting it all together, when the sed
-like "flip-flop" operator encounters a full match in both (start,stop) halves of the fff
regex operator, $i
gets incremented to 1, and thus last
s out of the loop, so only the first complete match is put
. [If you want to output all matches, simply omit the {last if $i++ == 1}
code block].
Note, it's simple enough to omit the two 'sentinal' lines in the return by changing fff
to ^fff^
, giving the following result:
Sample Output (2):
content1
content2
Further testing: All code above handles the case where P2 comes before P1. Additionally, all code above handles the case where P1 and P2 occur on the same line, WITHOUT terminating prematurely. If such "single line text blocks" are desired/preferred in the output, use Raku's "non-sed-like" ff
operator instead of the fff
operator.
https://docs.raku.org/routine/fff
https://raku.org