App-pl
view release on metacpan or search on metacpan
pod/examples.pod view on Meta::CPAN
=head1 NAME
pl-examples - Perl One-Liner Examples
=head1 EXAMPLES
I<To steal ideas from one person is plagiarism. To steal from many is research. ;-)>
Here's a wide variety of examples, many solving real-life problems. Often you
can copy & paste them as-is. Or you need to make minor changes, e.g. to adapt
them to your search expression. Many of these examples started out quite
small, illustrating the power of pl. But in order to be generally useful,
they have been extended to cope with border cases. See L<canned
commands|https://metacpan.org/dist/App-pl/view/pod/canned-commands.pod> for how you can make your favourite ones easier to
use.
Only some of these are original. Many have been adapted from the various Perl
one-liner webpages
(L<Tom Christiansen|http://softpanorama.org/Scripting/Perlorama/One-liners/tom_christiansen_one-liners.shtml>,
L<Peteris Krumins|https://nostarch.com/perloneliners>,
L<CatOnMat|https://catonmat.net/introduction-to-perl-one-liners>,
L<joyrexus|https://gist.github.com/joyrexus/7328094>,
L<Richard Socher|http://kiswebformations.wordpress.com/2015/04/04/perl-scripts-and-one-liners/>,
L<eduonix|https://blog.eduonix.com/perl-programming/learn-one-liners-perl-programming/>,
L<IBM 101|http://calmar.ws/linux/perl/One-liners101.html>,
L<IBM 102|https://www.ibm.com/developerworks/library/l-p102/>,
L<Oracle|https://blogs.oracle.com/linux/the-top-10-tricks-of-perl-one-liners-v2>,
L<PerlMonks|https://perlmonks.org/?node_id=502261>,
L<perloneliner|https://twitter.com/perloneliner>)
or videos
(L<Walt Mankowski|https://youtu.be/IGe0GnlIWq4>,
L<Techalicious|https://youtu.be/gbZAABq4uZk?t=284>,
L<David Oswald|https://youtu.be/euj54cqpGOE>).
This is no attempt to appropriate ownership, just to show how things are even
easier and more concise with pl.
=head2 Dealing with Files
=over
=item Heads ...
I<People say the back of my head looks really nice -- but I don't see it. :-)>
If you want just I<n>, e.g. 10, lines from the head of each file, use the
optional number argument to B<-p>, along with B<-r> to reset the count. The
program can be empty, but must be present, unless you're reading from stdin:
pl -rp10 '' file*
If you want the head up to a regexp, use the flip-flop operator, starting with
line number 1. Use the print-if-true B<-P> loop option, again with B<-r> to
reset the count:
pl -rP '1../last/' file*
You can combine the two, if you want at most I<n> lines, e.g. 10:
pl -rP10 '1../last/' file*
=item ... or Tails?
I<What has a head, a tail, but no legs? B< >A penny. :-)>
If you want a bigger number of last lines, you need to stuff them in a list;
not really worth it. But if you want just 1 last line from each file, the
end-of-file B<-e> code (no need to quote, as it has no special characters) can
C<E(cho)> it for you, capitalized so as to not add another newline (yes, Perl
is case sensitive):
pl -e Echo '' file*
pl -e E '' file*
If you want the tail from a line-number (e.g. 99) or a regexp, use the
flip-flop operator, starting with your regexp and going till each end-of-file:
pl -P '99..eof' file*
pl -P '/first/..eof' file*
You can even get head and tail (which in programming logic translates to print
if in 1st C<or> 2nd range), if last line of head comes before 1st line of tail
(or actually any number of such disjoint ranges):
pl -rP '1../last/ or /first/..eof' file*
=item Remove Trailing Whitespace in Each File
This print-loops (B<-p>) over each file, replacing it (B<-i>) with the
modified output. Line ends are stripped on reading and added on printing
(B<-l>), because they are also whitespace (C<\s>). At each end of line,
substitute one or more spaces of any kind (incl. DOS newlines) with nothing:
pl -pli 's/\s+$//' file*
=item Tabify/Untabify Each File
This print-loops (B<-p>) over each file, replacing it (B<-i>) with the
modified output. At beginning of line and after each tab, 8 spaces or less
than 8 followed by a tab are converted to a tab:
pl -pi '1 while s/(?:^|\t)\K(?: {1,7}\t| {8})/\t/' file*
To go the other way, subtract the tab-preceding length modulo 8, to get the
pod/examples.pod view on Meta::CPAN
> -r--r--r-- Steve/None 347 2019-10-24 22:17
> -r--r--r-- Steve/None 347 2019-10-21 13:20
> .metaconf-exclusions.txt
> -r--r--r-- sawyer/sawyer 1317 2019-05-11 11:50
> -r--r--r-- Steve/None 1317 2019-10-24 22:17
> -r--r--r-- Steve/None 1317 2019-10-24 22:17
> -r--r--r-- Steve/None 1317 2019-10-21 13:20
> .travis.yml
> -r--r--r-- sawyer/sawyer 2203 2019-05-11 11:50
> -r--r--r-- Steve/None 2203 2019-10-24 23:27
> -r--r--r-- Steve/None 2203 2019-10-24 23:27
> -r--r--r-- Steve/None 2203 2019-10-21 13:20
> AUTHORS
> -r--r--r-- sawyer/sawyer 48831 2019-05-11 11:50
> -r--r--r-- Steve/None 48864 2019-10-24 23:27
> -r--r--r-- Steve/None 48927 2020-02-29 12:55
> -r--r--r-- Steve/None 48927 2020-02-11 14:31
> Artistic
> -r--r--r-- sawyer/sawyer 6321 2019-05-11 11:50
> -r--r--r-- Steve/None 6321 2019-10-24 22:17
> -r--r--r-- Steve/None 6321 2019-10-24 22:17
> -r--r--r-- Steve/None 6321 2019-10-21 13:20
> Changes
> -r--r--r-- sawyer/sawyer 3168 2018-06-27 13:17
> -r--r--r-- Steve/None 3111 2019-10-27 10:52
> -r--r--r-- Steve/None 3111 2019-10-27 10:52
> -r--r--r-- Steve/None 3111 2019-10-28 09:05
> ...
Again without the date and owner/group, which can also vary:
pl -o 'piped {
keydiff $2
if s!^[^d]\S+ \K.+? +(\d+) .{16} [^/]+/(.+)!Form "%10d", $1!e;
} "tar", "-tvf", $_' *.tar *.tgz *.txz
pl -o 'p {
k $2
if s!^[^d]\S+ \K.+? +(\d+) .{16} [^/]+/(.+)!F "%10d", $1!e;
} "tar", "-tvf", $_' *.tar *.tgz *.txz
> AUTHORS
> -r--r--r-- 48831
> -r--r--r-- 48864
> -r--r--r-- 48927
> -r--r--r-- 48927
> Changes
> -r--r--r-- 3168
> -r--r--r-- 3111
> -r--r--r-- 3111
> -r--r--r-- 3111
> Configure
> -r-xr-xr-x 587687
> -r-xr-xr-x 587687
> -r-xr-xr-x 587825
> -r-xr-xr-x 587825
> ...
=item Diff ELF Executables by Loaded Dependencies
You get the idea: you can do this for any command that outputs records with a
unique key. This one looks at the required libraries and which file they came
from. For a change, loop with B<-O> and C<$A(RGV)> to avoid the previous
examples' confusion between outer C<$_> which were the cli args, and the inner
one, which were the read lines:
pl -O 'piped {
keydiff if s/^\t(.+\.so.*) => (.*) \(\w+\)/$2/;
} ldd => $ARGV' exe1 exe2 lib*.so
pl -O 'p {
k if s/^\t(.+\.so.*) => (.*) \(\w+\)/$2/;
} ldd => $A' exe1 exe2 lib*.so
It's even more useful if you use just the basename as a key, because version
numbers may change:
pl -O 'piped {
keydiff $2 if s/^\t((.+)\.so.* => .*) \(\w+\)/$1/;
} ldd => $ARGV' exe1 exe2 lib*.so
pl -O 'p {
k $2 if s/^\t((.+)\.so.* => .*) \(\w+\)/$1/;
} ldd => $A' exe1 exe2 lib*.so
=back
=head2 Looking at Perl
I<A pig looking at an electric socket: "Oh no, who put you into that wall?" :)>
=over
=item VERSION of a File
Print the first line (B<-P1>) where the substitution was successful. To avoid
the hassle of protecting them from (sometimes multiple levels of) Shell
quoting, there are variables for single C<$q(uote)> & double C<$Q(uote)>:
pl -P1 's/.+\bVERSION\s*=\s*[v$Quote$quote]{0,2}([0-9.]+).+/$1/' pl
pl -P1 's/.+\bVERSION\s*=\s*[v$Q$q]{0,2}([0-9.]+).+/$1/' pl
> 0.63.2
For multple files, add the filename, and reset (B<-r>) the B<-P> count for each
file:
pl -rP1 's/.+\bVERSION\s*=\s*[v$Quote$quote]{0,2}([0-9.]+).+/$ARGV: $1/' *.pm
pl -rP1 's/.+\bVERSION\s*=\s*[v$Q$q]{0,2}([0-9.]+).+/$A: $1/' *.pm
=item Only POD or non-POD
You can extract either parts of a Perl file, with these commands. Note that
they don't take the empty line before into account. If you want that, and
you're sure the files adheres strictly to this convention, use the option
B<-00P> instead (not exactly as desired, the empty line comes after things,
but still, before next thing). If you want only the 1st POD (e.g. NAME &
SYNOPSIS) use the option B<-P1> or B<-00P1>:
pl -P '/^=\w/../^=cut/' file*
pl -P 'not /^=\w/../^=cut/' file*
=item Count Perl Code
( run in 1.744 second using v1.01-cache-2.11-cpan-39bf76dae61 )