Front page | perl.perl6.users |
Postings from July 2020
Re: Raku version of "The top 10 tricks of Perl one-liners" ?!?
Thread Previous
|
Thread Next
From:
Aureliano Guedes
Date:
July 22, 2020 20:32
Subject:
Re: Raku version of "The top 10 tricks of Perl one-liners" ?!?
Message ID:
CAG9gabSVNYh-OML3jn5R=GxAEL7+vwR3AsNysBYRydDEsCQrag@mail.gmail.com
That is a little bit disappointing:
$ time ls -l | perl -lane 'print "$F[7] $F[1]"' > /dev/null
real 0m0.008s
user 0m0.013s
sys 0m0.000s
$ time ls -l | raku -ne 'say "$_[7] $_[1]" given .words' > /dev/null
Use of Nil in string context
in block at -e line 1
real 0m0.302s
user 0m0.370s
sys 0m0.060s
The delay is so long that I wouldn't use that in a very filled folder.
Perhaps I know, it will be improved (I hope).
On Wed, Jul 22, 2020 at 4:21 PM Larry Wall <larry@wall.org> wrote:
> On Sun, Jul 19, 2020 at 09:38:31PM -0700, William Michels via perl6-users
> wrote:
> : Hello,
> :
> : I ran across this 2010 Perl(5) article on the Oracle Linux Blog:
> :
> : "The top 10 tricks of Perl one-liners"
> : https://blogs.oracle.com/linux/the-top-10-tricks-of-perl-one-liners-v2
> :
> : Q1. Now that it's a decade later--and Raku (née Perl6) has hit the
> : scene--can someone translate the 'top ten tricks' in the blog article
> : above into Raku?
> :
> : Q2. Are many of the ten Perl(5) one-liner 'tricks' unnecessary in Raku
> : (better defaults, more regularized regexes, etc.)?
> :
> : Best, Bill.
>
> Yes, and yes. :-)
>
> More specificially, here's my take.
>
> > Trick #1: -l
> >
> > Smart newline processing. Normally, perl hands you entire lines,
> > including a trailing newline. With -l, it will strip the trailing
> > newline off of any lines read, and automatically add a newline to
> > anything you print (including via -p).
> >
> > Suppose I wanted to strip trailing whitespace from a file. I might
> > naïvely try something like
> >
> > perl -pe 's/\s*$//'
> >
> > The problem, however, is that the line ends with "\n", which is
> > whitespace, and so that snippet will also remove all newlines from
> > my file! -l solves the problem, by pulling off the newline before
> > handing my script the line, and then tacking a new one on
> afterwards:
> >
> > perl -lpe 's/\s*$//'
>
> This trick is not needed in Raku, since newlines are stripped by default.
> Also,
> there are .trim methods that you can use instead of regex.
>
> > Trick #2: -0
> >
> > Occasionally, it's useful to run a script over an entire file,
> > or over larger chunks at once. -0 makes -n and -p feed you chunks
> > split on NULL bytes instead of newlines. This is often useful for,
> > e.g. processing the output of find -print0. Furthermore, perl
> -0777
> > makes perl not do any splitting, and pass entire files to your
> script
> > in $_.
> >
> > find . -name '*~' -print0 | perl -0ne unlink
> >
> > Could be used to delete all ~-files in a directory tree, without
> > having to remember how xargs works.
>
> The key word above is "occasionally", so most of these seldom-used
> switches are gone.
> Also, most of their functions are really easy to do from inside the
> language.
> So these days dividing a file by null chars would typicaly be handled with:
>
> for slurp.split("\0") { ... }
>
> > Trick #3: -i
> >
> > -i tells perl to operate on files in-place. If you use -n or -p
> with
> > -i, and you pass perl filenames on the command-line, perl will run
> > your script on those files, and then replace their contents with
> the
> > output. -i optionally accepts an backup suffix as argument; Perl
> will
> > write backup copies of edited files to names with that suffix
> added.
> >
> > perl -i.bak -ne 'print unless /^#/' script.sh
> >
> > Would strip all whole-line commands from script.sh, but leave a
> copy
> > of the original in script.sh.bak.
>
> I'm not aware of a direct replacement for this in Raku. Perl has to be
> better at something...
>
> > Trick #4: The .. operator
> >
> > Perl's .. operator is a stateful operator -- it remembers state
> > between evaluations. As long as its left operand is false, it
> returns
> > false; Once the left hand returns true, it starts evaluating the
> > right-hand operand until that becomes true, at which point, on
> > the next iteration it resets to false and starts testing the other
> > operand again.
> >
> > What does that mean in practice? It's a range operator: It can be
> > easily used to act on a range of lines in a file. For instance,
> > I can extract all GPG public keys from a file using:
> >
> > perl -ne 'print if /-----BEGIN PGP PUBLIC KEY
> BLOCK-----/../-----END PGP PUBLIC KEY BLOCK-----/' FILE
>
> The scalar .. operator in Perl translates to the ff operator in Raku.
> It's slightly less magical, however, insofar as it won't treat bare
> numbers as line numbers in the input.
>
> > Trick #5: -a
> >
> > -a turns on autosplit mode – perl will automatically split input
> > lines on whitespace into the @F array. If you ever run into any
> advice
> > that accidentally escaped from 1980 telling you to use awk because
> > it automatically splits lines into fields, this is how you use
> perl
> > to do the same thing without learning another, even worse,
> language.
> >
> > As an example, you could print a list of files along with their
> link
> > counts using
> >
> > ls -l | perl -lane 'print "$F[7] $F[1]"'
>
> This feature was always a bit suspect because it hard-wired a particular
> name. You don't even need a weird name in Raku:
>
> ls -l | raku -ne 'say "$_[7] $_[1]" given .words'
>
> > Trick #6: -F
> >
> > -F is used in conjunction with -a, to choose the delimiter on
> > which to split lines. To print every user in /etc/passwd (which is
> > colon-separated with the user in the first column), we could do:
> >
> > perl -F: -lane 'print $F[0]' /etc/passwd
>
> Again, we felt this switch wasn't really pulling it's weight, so we pulled
> it
> in favor of explicit split or comb:
>
> raku -ne 'say $_[0] given .split(":")' /etc/passwd
>
> > Trick #7: \K
> >
> > \K is undoubtedly my favorite little-known-feature of Perl regular
> > expressions. If \K appears in a regex, it causes the regex
> matcher to
> > drop everything before that point from the internal record of
> "Which
> > string did this regex match?". This is most useful in conjunction
> > with s///, where it gives you a simple way to match a long
> expression,
> > but only replace a suffix of it.
> >
> > Suppose I want to replace the From: field in an email. We could
> > write something like
> >
> > perl -lape 's/(^From:).*/$1 Nelson Elhage <nelhage\@ksplice.com
> >/'
> >
> > But having to parenthesize the right bit and include the $1 is
> > annoying and error-prone. We can simplify the regex by using \K to
> > tell perl we won't want to replace the start of the match:
> >
> > perl -lape 's/^From:\K.*/ Nelson Elhage <nelhage\@ksplice.com>/'
>
> Perl's \K \k becomes <( )> in Raku. Note that there are other regex
> changes as well,
> and that in the replacement it's not necessary to escape the @ in the
> absence of brackets:
>
> raku -pe 's/ ^ "From:" <(.*)> / Nelson Elhage <nelhage@ksplice.com>/'
>
> The )> is not required to balance there, but helps clarify the intention.
> If you do
> have a quoting problem in the replacement, you can use the assignment form
> with
> any other form of quoting instead:
>
> raku -pe 's[ ^ "From:" <(.*)> ] = Q[Nelson Elhage <
> nelhage@ksplice.com>]'
>
> > Trick #8: $ENV{}
> >
> > When you're writing a one-liner using -e in the shell, you
> generally
> > want to quote it with ', so that dollar signs inside the one-liner
> > aren't expanded by the shell. But that makes it annoying to use a
> '
> > inside your one-liner, since you can't escape a single quote
> inside
> > of single quotes, in the shell.
> >
> > Let's suppose we wanted to print the username of anyone in
> /etc/passwd
> > whose name included an apostrophe. One option would be to use a
> > standard shell-quoting trick to include the ':
>
> > perl -F: -lane 'print $F[0] if $F[4] =~ /'"'"'/' /etc/passwd
> >
> > But counting apostrophes and backslashes gets old fast. A better
> > option, in my opinion, is to use the environment to pass the regex
> > into perl, which lets you dodge a layer of parsing entirely:
> >
> > env re="'" perl -F: -lane 'print $F[0] if $F[4] =~ /$ENV{re}/'
> /etc/passwd
> >
> > We use the env command to place the regex in a variable called re,
> > which we can then refer to from the perl script through the %ENV
> > hash. This way is slightly longer, but I find the savings in
> counting
> > backslashes or quotes to be worth it, especially if you need to
> end
> > up embedding strings with more than a single metacharacter.
>
> This is rather Unix-centric on the face of it, since on Windows you'd
> have to use outer "" quoting instead. But you can certainly use the
> same trick with Raku, provided you spell ENV right:
>
> env re="'" raku -ne '(say .[0] if .[4] ~~ /<{ %*ENV<re> }>/) given
> .split(":")' /etc/passwd
>
> It probably won't be very efficient though, and doesn't do a thing for
> readability.
> Much easier to use a character name:
>
> raku -ne '(say .[0] if .[4] ~~ /\c[APOSTROPHE]/) given .split(":")'
> /etc/passwd
>
> You could backport that trick to Perl using \N{} too, I guess.
>
> > Trick #9: BEGIN and END
> >
> > BEGIN { ... } and END { ... } let you put code that gets run
> entirely
> > before or after the loop over the lines.
> >
> > For example, I could sum the values in the second column of a CSV
> > file using:
> >
> > perl -F, -lane '$t += $F[1]; END { print $t }'
>
> Same trick, except you can omit the brackets:
>
> raku -ne 'my $t += [1] given .split(","); END say $t'
>
> Note the 'my' is required because strict is the default.
>
> > Trick #10: -MRegexp::Common
> >
> > Using -M on the command line tells perl to load the given module
> > before running your code. There are thousands of modules available
> > on CPAN, numerous of them potentially useful in one-liners, but
> > one of my favorite for one-liner use is Regexp::Common, which, as
> > its name suggests, contains regular expressions to match numerous
> > commonly-used pieces of data.
> >
> > The full set of regexes available in Regexp::Common is available
> in
> > its documentation, but here's an example of where I might use it:
> >
> > Neither the ifconfig nor the ip tool that is supposed to replace
> it
> > provide, as far as I know, an easy way of extracting information
> for
> > use by scripts. The ifdata program provides such an interface, but
> > isn't installed everywhere. Using perl and Regexp::Common,
> however,
> > we can do a pretty decent job of extracing an IP from ips output:
> >
> > ip address list eth0 | \
> > perl -MRegexp::Common -lne 'print $1 if /($RE{net}{IPv4})/'
>
> I don't know if there's anything quite comparable. And who's to say
> what's "common" anymore... Certainly we have -M. But Raku's regex
> and grammars are so much more powerful that these things are likely to
> kept in more specific Grammar modules anyway, or just hand-rolled for
> the purpose on the spot.
>
> > ~nelhage Join the discussion Comments ( 7 )
>
> Larry
>
--
Aureliano Guedes
skype: aureliano.guedes
contato: (11) 94292-6110
whatsapp +5511942926110
Thread Previous
|
Thread Next