print everything after a line matching a pattern

4 views
Skip to first unread message

Rainer Weikusat

unread,
Feb 9, 2021, 4:11:03 PMFeb 9
to
First use I've ever found for the perl range operator:

perl -ane '// .. /Reverse Provides/ or print $F[0], "\n"'

This reads lines from stdin until one matching /Reverse Provides/ is
encountered and prints everything line after that.

George Bouras

unread,
Feb 11, 2021, 3:23:10 AMFeb 11
to
Στις 9/2/2021 11:10 μ.μ., ο/η Rainer Weikusat έγραψε:
> First use I've ever found for the perl range operator:
>
> perl -ane '// .. /Reverse Provides/ or print $F[0], "\n"'
>
perl -ane '$a && print; /foo/ and $a=1'

Ben Bacarisse

unread,
Feb 11, 2021, 6:34:32 AMFeb 11
to
George Bouras <f...@example.com> writes:

> Στις 9/2/2021 11:10 μ.μ., ο/η Rainer Weikusat έγραψε:
>> First use I've ever found for the perl range operator:
>>
>> perl -ane '// .. /Reverse Provides/ or print $F[0], "\n"'

This does not print lines matching the right pattern in the range, so it
does not do exactly what the subject line says.

It took me a while to work out what's really going on because the use of
//, with it's special meaning, makes the whole thing a bit too tricksy
for me (and I like tricksy!). I'm still not sure what Perl says about
using m// before any match has succeeded.

> perl -ane '$a && print; /foo/ and $a=1'

I think this is clearer (though I might use a name like $seen rather
than $a) and it does do exactly what the subject line says.

--
Ben.

Rainer Weikusat

unread,
Feb 11, 2021, 8:35:08 AMFeb 11
to
Ben Bacarisse <ben.u...@bsb.me.uk> writes:
> George Bouras <f...@example.com> writes:
>
>> Στις 9/2/2021 11:10 μ.μ., ο/η Rainer Weikusat έγραψε:
>>> First use I've ever found for the perl range operator:
>>>
>>> perl -ane '// .. /Reverse Provides/ or print $F[0], "\n"'
>
> This does not print lines matching the right pattern in the range, so it
> does not do exactly what the subject line says.

The subject says "everything after" and that's what it does: The
separator is not supposed to be included.

> It took me a while to work out what's really going on because the use of
> //, with it's special meaning, makes the whole thing a bit too tricksy
> for me (and I like tricksy!). I'm still not sure what Perl says about
> using m// before any match has succeeded.

If no match has previously succeeded, this will (silently) act instead
as a genuine empty pattern (which will always match).
[perldoc perlop]

>> perl -ane '$a && print; /foo/ and $a=1'
>
> I think this is clearer (though I might use a name like $seen rather
> than $a) and it does do exactly what the subject line says.

It's obviously possible to imitate the built-in operator using a
(miniature) state machine. But as there's a built-in operator which can
serve the exact same function (and one I haven't found any use for so
far), I considered this more worth of writing about it.

Ben Bacarisse

unread,
Feb 11, 2021, 10:42:42 AMFeb 11
to
Rainer Weikusat <rwei...@talktalk.net> writes:

> Ben Bacarisse <ben.u...@bsb.me.uk> writes:
>> George Bouras <f...@example.com> writes:
>>
>>> Στις 9/2/2021 11:10 μ.μ., ο/η Rainer Weikusat έγραψε:
>>>> First use I've ever found for the perl range operator:
>>>>
>>>> perl -ane '// .. /Reverse Provides/ or print $F[0], "\n"'
>>
>> This does not print lines matching the right pattern in the range, so it
>> does not do exactly what the subject line says.
>
> The subject says "everything after" and that's what it does: The
> separator is not supposed to be included.

I think there is some ambiguity in the wording.

$ cat t
a
b
x
c
d
x
e
$ perl -ane '// .. /x/ or print $F[0], "\n"' t ✘
c
d
e
$

I assumed you'd want the second x line printed since it follows a match,
but of course it is also, at the same time, a match itself.

>> It took me a while to work out what's really going on because the use of
>> //, with it's special meaning, makes the whole thing a bit too tricksy
>> for me (and I like tricksy!). I'm still not sure what Perl says about
>> using m// before any match has succeeded.
>
> If no match has previously succeeded, this will (silently) act instead
> as a genuine empty pattern (which will always match).
> [perldoc perlop]

Ah, thanks. I searched but could not find that. Maybe I only looked
in perlre.

>>> perl -ane '$a && print; /foo/ and $a=1'
>>
>> I think this is clearer (though I might use a name like $seen rather
>> than $a) and it does do exactly what the subject line says.
>
> It's obviously possible to imitate the built-in operator using a
> (miniature) state machine. But as there's a built-in operator which can
> serve the exact same function (and one I haven't found any use for so
> far), I considered this more worth of writing about it.

If you want the behaviour that you actually get with //../pattern/ then
this code is not equivalent. I agree that the state-machine equivalent
of the original would be messier.

--
Ben.

Rainer Weikusat

unread,
Feb 11, 2021, 11:13:27 AMFeb 11
to
Ben Bacarisse <ben.u...@bsb.me.uk> writes:

[...]


>>>>> perl -ane '// .. /Reverse Provides/ or print $F[0], "\n"'

[...]

>>>> perl -ane '$a && print; /foo/ and $a=1'
>>>
>>> I think this is clearer (though I might use a name like $seen rather
>>> than $a) and it does do exactly what the subject line says.
>>
>> It's obviously possible to imitate the built-in operator using a
>> (miniature) state machine. But as there's a built-in operator which can
>> serve the exact same function (and one I haven't found any use for so
>> far), I considered this more worth of writing about it.
>
> If you want the behaviour that you actually get with //../pattern/ then
> this code is not equivalent. I agree that the state-machine equivalent
> of the original would be messier.

Thanks for pointing this out: The difference (start printing after the
first Reverse Provides and but all later lines containing this text)
doesn't matter for my use-case but technically, what I wanted was

1 .. /Reverse Provides/

Rainer Weikusat

unread,
Feb 11, 2021, 11:14:13 AMFeb 11
to
Ben Bacarisse <ben.u...@bsb.me.uk> writes:

[...]


>>>>> perl -ane '// .. /Reverse Provides/ or print $F[0], "\n"'

[...]

>>>> perl -ane '$a && print; /foo/ and $a=1'
>>>
>>> I think this is clearer (though I might use a name like $seen rather
>>> than $a) and it does do exactly what the subject line says.
>>
>> It's obviously possible to imitate the built-in operator using a
>> (miniature) state machine. But as there's a built-in operator which can
>> serve the exact same function (and one I haven't found any use for so
>> far), I considered this more worth of writing about it.
>
> If you want the behaviour that you actually get with //../pattern/ then
> this code is not equivalent. I agree that the state-machine equivalent
> of the original would be messier.

Thanks for pointing this out: The difference (start printing after the
first Reverse Provides and omit all later lines containing this text)

Ben Bacarisse

unread,
Feb 11, 2021, 11:35:55 AMFeb 11
to
Now that's a clean use of the range operator. The specific behaviour of
the original results from a number of somewhat (at least to me)
unexpected consequences:

// won't match most lines after /Reverse Provides/ matches because it
no longer means a literal empty match.

// will match a following line with 'Reverse Provides', making the
range expression true again.

.. (in contrast to ...) immediately tests the right-hand expression as
well so the range expressions switches to false on the same input
line.

But the switch to being false does not take place until the range
expression is tested again on the next line, so the expression returns
true exactly once causing the line that opens and closes the range to
be printed.

It took me longer that I'd like to admit to work that out, but I must
thank you for prompting me to study it.

--
Ben.
Reply all
Reply to author
Forward
0 new messages