++ed by:
2 non-PAUSE users
Author image Daniel Pfeiffer


pl - Perl One-Liner Magic Wand


There are always those tasks too menial for dedicated script, but still too cumbersome even with the many neat one-liner options of perl -E. This small script fills the gap with many bells & whistles: Various one-letter commands & magic variables (with meaningful aliases too) and more nifty loop options take Perl programming to the command line. List::Util is fully imported. If you pass no program on the command line, starts a simple Perl Shell.

How to e(cho) values, including from @A(RGV), with single $q(uote) & double $Q(uote):

    pl 'echo "${quote}Perl$quote", "$Quote@ARGV$Quote"' one liner
    pl 'e "${q}Perl$q", "$Q@A$Q"' one liner

    >   'Perl' "one liner"

Same for hard-to-print values:

    pl 'echo \"Perl", \@ARGV, undef' one liner
    pl 'e \"Perl", \@A, undef' one liner

    >   \'Perl' [
    >     'one',
    >     'liner'
    >   ] undef

Loop over args, printing each with line ending. And same, SHOUTING:

    pl -opl '' Perl one liner
    pl -opl '$_ = uc' Perl one liner

    >   Perl
    >   one
    >   liner
    >   PERL
    >   ONE
    >   LINER

Print up to 3 matching lines, resetting count (and $.) for each file:

    pl -rP3 '/Perl.*one.*liner/' file*

Count hits in magic statistics hash %N(UMBER):

    pl -n '++$NUMBER{$1} while /(Perl|one|liner)/g' file*
    pl -n '++$N{$1} while /(Perl|one|liner)/g' file*

    >          2: one
    >          7: liner
    >          9: Perl

Though they are sometimes slightly, sometimes quite a bit more complicated, most Perl one-liners from the internet work, just by omitting -e or -E (pl has only one main program, but you can just as well concatenate the -es with ;). See minor differences for exceptions. There are many varied examples.


Don't believe everything you read on SourceForge^H^H^H the internet! -- Aristotle ;-)

Pl follows Perl's philosophy for one-liners: the one variable solely used in one-liners, @F, is single-lettered. Because not everyone may like that, Pl has it both ways. Everything is aliased both as a word and as a single letter, including Perl's own @F & *ARGV.

Perl one-liners, and hence pl, are by nature bilingual. You must run the command with its options & arguments, typically from Shell. By design, Perl quotes mimic Shell quotes, so here they collide. As Perl also uses Shell meta-characters like $, the best solution is to protect Perl-code from the Shell with single quotes. That means they can't be used inside. (An ugly way around that is '\'', which ends a string, blackslashes a quote and starts another.) For literal quotes use $q(uote). For quoting use double quotes or q{}.

Shell and Perl, unlike most other languages, don't make you stick your toe up your nose to get newlines into strings. So, long "one-liners" are spread very naturally to legible many-liners. You get more features on the pl homepage, like in the veggie-burger menu, you can toggle many-line display. In normal text short and long name variants are initial-bold as X(YZ). All examples use the long names, if applicable. On the homepage those are in the darker blue upper half. They are repeated with the short variant. Many examples are followed by their output, indented with >.



Many of perl's options are also available in pl, sometimes enhanced with extra functionality. And the new options complement what perl offers, specifically oriented towards one liners.


perl: Specify record separator with -n/-p (\0, if no argument).


Map program over already available @A(RGV) (from command line or previous -A) or undef. The result becomes the new @A(RGV). May be mixed with -B.


perl: Autosplit mode with -n/-p (splits $_ into @F(IELD)).


Run program before reading a new file in -n/-p.


Add program before main program in same scope. So you can use it to initialise my variables. Whereas, if you define a my variable in the main program of a -n, -p, -P, -o or -O loop, it's a new variable on each iteration. This doesn't do a BEGIN block, unless program is wrapped in {}. May be mixed with -A.


perl: Check syntax only (runs BEGIN and CHECK blocks).


perl: Enables the listed Unicode features.


Colorize (people with impairment have hopefully adapted their system or browser) some of the output; when can be never, always, or auto (the default).


perl: Run program under debugger.


perl: Set debugging flags (argument is a bit mask or alphabets).


Run program after finishing reading a file in -n/-p.


Add an END block after main-program in same scope. So my-vars work as follows: The END block is a closure of the 1st $inner variable. Perl warns "Variable "$inner" will not stay shared":

    pl -OB 'my $outer' -E 'echo $inner, $outer' 'my $inner = $outer = $ARGV' a b c
    pl -OB 'my $outer' -E 'e $inner, $outer' 'my $inner = $outer = $A' a b c

    >   a c

perl: Don't do $sitelib/sitecustomize.pl at startup.


perl: Provide split() pattern for -a switch (//'s are optional).


perl: Specify @INC/#include directory (several -I's allowed).


perl: Edit <> files in place (makes backup if extension supplied).


As I said before, I never repeat myself. :-)

perl: Assume while (<>) { ... } loop around program. It's a little richer than that: if you use last, it closes the current file, leaving you to continue the loop on the next file.


Assume for(@ARGV) { ... } loop around main program, and $ARGIND (or $I) is the current position. In this case -p doesn't imply -n. If number is given, that many args are passed at once as an array, referencing the original values. If there are not enough on the last round, @A(RGV) is filled up with undef.

    pl -opl '' I II III IV
    pl -o3 'echo $ARGIND, @$_' i ii iii iv v vi vii viii ix
    pl -opl '' I II III IV
    pl -o3 'e $I, @$_' i ii iii iv v vi vii viii ix

    >   I
    >   II
    >   III
    >   IV
    >   0 i ii iii
    >   3 iv v vi
    >   6 vii viii ix

like -o, but use @A(RGV) as loop variable.


Does pl -penis do pussy? It implements cat. :-*

perl++: On each loop print (also -o and -O, in which case you must fill $_) iteration. If number is given, print at most number times.


Like -p, but print only if main program evaluates to true, like grep.


Reset $. and -p/-P counter for each file.


perl: Enable tainting checks.


perl: Enable tainting warnings.


perl: Allow unsafe operations.


perl: Dump core after parsing program.


perl: Print version, patchlevel and license.


Rerun with given perl version, which is just a string appended to perl.


perl: Enable all warnings.


perl: Enable many useful warnings.


perl: Disable all warnings.


There are various functions, always also with a one letter alias, which perform little tasks that can be useful in one liners.

benchmark { } [name[, arg...]] | b { } [name[, arg...]]

Benchmark slow code for 10s, display name, looping over args.

Benchmark { } [name[, arg...]] | B { } [name[, arg...]]

Same, but run code 100 times in benchmark, to reduce overhead.

Config [regexp...] | C [regexp...]

Import and return %Config, e.g. Config->{sitelib}, optionally only part matching regexps.

Date [arg...][, tz] | D [arg...][, tz]

Why is Halloween Christmas? Because Oct 31 = Dec 25. (^)

Date (from arg [s, us], s{.us}, offset [+-]s{.us}, tz ([+-]0-14{:mm|.ff}). Microseconds should be passed as strings, because floats have implementation-dependent rounding issues. Positive offsets must be passed as strings, because otherwise the + gets lost. Returns the date, if called in some context, else echoes it.

    pl 'Date;
        $_ = Date -86400, "+3600";
        e $_, " -- ", Date "+8:45"'
    pl 'D;
        $_ = D -86400, "+3600";
        e $_, " -- ", D "+8:45"'

    >   Thu Jan  6 23:44:02.147683 2022
    >   Thu Jan  6 00:44:02.147744 2022  --  Fri Jan  7 07:29:02.147769 +08:45 2022
echo [arg...] | e [arg...]

Echo prettified args or $_ with spaces and newline. Prettified means, undef becomes that string, italic if --color is active. Anything that can be stringified, is. Any other reference goes through Data::Dumper, which is loaded only if needed.

If it is called in scalar context (e.g. $x = echo ...) instead return the same as it would echo, in one string (inspired by Shell $(...)). If it is called in list context (e.g. @l = echo ...) return each arg prettified individually, with a newline on the last one.

Echo [arg...] | E [arg...]

Same, but no newline.

form format, [arg...] | f format, [arg...]

Form(at) and echo prettified args or $_ with newline. If it is called in scalar or list context (e.g. $x = form ...) instead return the same as it would echo, in one string. Parameter index can be "%1:" instead of "%1\$".

Form format, [arg...] | F format, [arg...]

Same, but no newline.

Isodate [arg...][, tz] | I [arg...][, tz]

Same as D(ate), but uses ISO format.

    pl 'Isodate;
        $_ = Isodate 7 * -86400;
        e $_, " -- ", Isodate "+8.75"'
    pl 'I;
        $_ = I 7 * -86400;
        e $_, " -- ", I "+8.75"'

    >   2022-01-06T23:44:02.165406
    >   2021-12-30T23:44:02.165471  --  2022-01-07T07:29:02.165494 +08:45
keydiff [key[, value]] | k [key[, value]]

Store value or chomped $_ in $KEYDIFF{key or $1}[$ARGIND]. At the END for each key (sorted numerically if possible) all values are diffed.

Keydiff [number[, value]] | K [number[, value]]

Same, but key is $FIELD[number] or $F[0].

Number [n] | N [n]

Trim %N(UMBER) values less than n (default 2) e.g.; -ENumber or -E 'N 5'.

piped { } cmd[, arg...] | p { } cmd[, arg...]

Open pipe from cmd and loop over it.


There are various variables, always also with a one letter alias, many of which perform magic tasks at the END.

*ARGV | *A

perl: ARGV, $ARGV & @ARGV are all aliased to A, $A & @A.


Index of ARG currently being processed in -o, -n or -p.


perl: This is an alias to loop autosplit variable @F.

$quote | $q

Predefined to a single quote '. There is no magic associated. Perl's q() makes it easy to integrate functional quotes under all circumstances. This does the same for literal quotes.

$Quote | $Q

Predefined to a double quote ". There is no magic associated. Perl's qq() makes it easy to integrate functional quotes under all circumstances. This does the same for literal quotes.


At END, sort by keys, print keydiff of $ARGIND array elements. Filled by k(eydiff).


At END, sort numerically by values.


At END, echo $RESULT if defined, then @RESULT one per line if not empty, then %RESULT sorted by keys.


Since pl -MO=Deparse won't show your parts of the program, it can be quite baffling when things go wrong. If you export this before starting pl, you see how your parts get embedded in various bits of generated stuff. If you install perltidy, it will be used.

You will not see the effect of -a, -F or -n as those get wrapped around it by perl behind the scenes. Due to interfacing with those options and providing for various option-combinations, the generated code may be too complicated. Expect it to change and be optimized further in the future:

    PLDUMP=1 \
        pl 'say "Hello Perld!"'

    >   sub pl::prog {
    >       $pl::last = 1;
    >     LINE: {
    >   #line 1 "main program"
    >           say "Hello Perld!";
    >       } continue {
    >           $pl::last = 0;
    >       }
    >       if ( $pl::last || eof ) {
    >           ++$ARGIND;
    >           if ($pl::last) { my $d = $.; close ARGV; $. = $d }
    >           exit if $pl::last == 2;
    >       }
    >   }


Even if it is rare nowadays, Perl 5.10 is still found out in the wild. Pl tries to accomodate it gracefully, falling back to what works. It has shims for any, all, none, notall, product & sum0. Dumped data-structures may be formatted with a funny margin and h(osts) will find the less IPv6 resolutions, the older your Perl.

Minor Differences with perl -e

Known minor differences are:

  • don't goto LINE, but next LINE is fine

  • in a -n loop last is per file instead of behaving like exit

  • using pop, etc. to implicitly modify @A(RGV) works in -B begin code, but not in your main program (which gets compiled to a function)

  • shenanigans with unbalanced braces won't work

Windows Notes

Work Is Never Done On Windows Systems ;-)

Do yourself a favour and get a real Shell, e.g. from WSL, Cygwin, MSYS, MinGW or git! If you can't avoid command.com or cmd.exe, you will have to first convert all inner quotes to qq. Then convert the outer single quotes to double quotes:

    pl "echo qq{${quote}Perl$quote}, qq{$Quote@ARGV$Quote}" one liner
    pl "e qq{${q}Perl$q}, qq{$Q@A$Q}" one liner

    >   'Perl' "one liner"

Any help for getting this to work in PowerShell is welcome!

While the old Windows 10 terminal understands ANSI escape sequences, it makes it horribly hard to activate them. So they are off by default, requiring --color to override that choice.

Pl is maintained on SourceForge and also available on meta::cpan.