Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Inserting Code Before an -n/-p Loop

by haukex (Archbishop)
on Dec 17, 2018 at 20:51 UTC ( [id://1227366]=perlmeditation: print w/replies, xml ) Need Help??

Probably most people know about the "Eskimo greeting" "secret operator". I'm not sure if the following trick is common knowledge, but I just saw it for the first time in this blog post by Yary:

$ perl -MO=Deparse -M'5;print "foo"' -ne '}{print "bar"' sub BEGIN { require 5; () } print 'foo'; LINE: while (defined($_ = readline ARGV)) { (); } { print 'bar'; }

A neat little trick :-)

Replies are listed 'Best First'.
Re: Inserting Code Before an -n/-p Loop
by Eily (Monsignor) on Dec 18, 2018 at 10:03 UTC

    Neat trick indeed! When I read your post I immediatly thought about a problem I had a few weeks ago where I wished such a construct existed (BEGIN worked alright, but it makes the command a bit long and I like them to fit on one line :) ). Turns out my problem is exactly the one mentioned in the linked post. And Discipulus has a good point about being able to glob your arguments :)

    I was a little confused by the deparsed code because the print 'foo' doesn't come right after the 5; But it's just that -M'5; print "foo"' is actually turned into use 5; print 'foo'; and the first statement is turned into an equivalent BEGIN + require block :)

    It also works if you are already including a module without parameters

    perl -MO=Deparse -M"Data::Dump; print 'Hi'" -ne "" use Data::Dump; print 'Hi'; LINE: while (defined($_ = readline ARGV)) { (); } -e syntax OK
    It technically works with strict, but if you're going to use that kind of constructs you probably don't need strictures :P

    Also, if you want to say something in that BEGIN-like code, since the feature would only be added by -E after the inserted code, you'll have to do something like: -M'v5.10; say "just saying"'

    Edit: who needs O::Deparse anyway?

    perl -M"5.01;say q&" -Mstrict -anE " print 'Hi'; }&;{" ;use strict;use feature ':5.26';LINE: while (<>) {our @F=split(' '); print 'Hi'; }

Re: Inserting Code Before an -n/-p Loop
by LanX (Saint) on Dec 17, 2018 at 21:07 UTC
    I somehow remember seeing it in the perldocs, but not sure where.

    What's happening is that the snippet is literally injected into a loop (see perlrun)

    }{ is just closing the loops body and opening a block to pair with the old end.

    Nota bene that using BEGIN and END blocks have similar effects but are probably easier to read.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

    update

    from perlrun#*-n*

  • -n

    causes Perl to assume the following loop around your program, which makes it iterate over filename arguments somewhat like sed -n or awk:

    LINE: while (<>) { ... # your program goes here }

    ...

    BEGIN and END blocks may be used to capture control before or after the implicit program loop, just as in awk.

Re: Inserting Code Before an -n/-p Loop -- oneliner
by Discipulus (Canon) on Dec 18, 2018 at 09:32 UTC
    hello haukex,

    Yes, thanks, a neat little trick.

    It will be useful, for example, in unfortunate shells that does not do glob expansions of the arguments. To count lines of code in test files you can glob them using your trick (I was used to put a BEGIN block there):

    perl -M"5;@ARGV=glob shift" -lnE "last if /__DATA__/;$c++ unless /^$|^ +\s*#/}{say $c" "./t/*.t"

    I didnt recognize what that 5 was for; manual to the rescue! require N requires a minimal version of Perl, so numbers from 0 to 5 will be all ok. Zero is more hackish ;)

    This neat trick is worth to be added to shh.. dont tell! manpage (update: done!). If I can suggest a name, being the opposite of eskimo greeting I propose maori farewell

    That said, i cant resist to use the maori farewell immediately..

    perl -M"0;eval{require 6},@}=(40,35,0,32)" -e "print map{chr(ord($_)-s +hift@})}(split'',$@)[12,19,0,23]" # linux quoting: perl -M'0;eval{require 6},@}=(40,35,0,32)' -e 'print map{chr(ord($_)-s +hift@})}(split"",$@)[12,19,0,23]'

    L*

    UPDATE April 25 2019: in December I suggested to add this trick to perlsecret and is now part of perlsecret 1.014

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

      Zero is more hackish ;)

      "-6"!! That will teach them a lesson!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://1227366]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (5)
As of 2024-03-29 13:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found