Perl Part I · Module 15 · Command-Line Perl and Script Execution
One-Liners: perl -e
Not every job deserves a file. Counting how many lines of a report mention a particular pin, converting a column of picoseconds to nanoseconds, checking whether two netlists have the same set of names — these take one line, you will do them once, and creating a script for them is slower than doing them. perl -e takes the whole program as a command-line argument and runs it immediately. The flags that go with it turn a cramped expression into something readable, and the one thing that genuinely catches people out is not Perl at all: it is the shell, which reads your program text before Perl does and will quietly rewrite parts of it unless you quote it correctly.
Intermediate13 min readPerlPart ICommand Line
Part I · Module 15 · Chapter 15.6 · One-Liners: perl -e
1. The Whole Idea
perl -e 'print "hello\n"'-e says "the next argument is the program". There is no file, nothing is saved, and Perl exits when it finishes. Everything the language can do is available — this is not a cut-down mode.
use strict;
use warnings;
# each row runs a real one-liner and shows what came back
my @demo = (
[ q{perl -e 'print "hello\n"'}, "the simplest form" ],
[ q{perl -e 'my $x = 6;' -e 'print $x*7, "\n"'}, "two -e options, one program" ],
[ q{perl -E 'say "say needs -E"'}, "-E switches on modern features" ],
[ q{perl -le 'print "l adds the newline"'}, "-l appends a newline to print" ],
[ q{perl -e 'print 2**10, "\n"'}, "any expression at all" ],
);
for my $d (@demo) {
my ($cmd, $why) = @$d;
my $out = `$cmd 2>&1`;
$out =~ s/\s+\z//;
printf "%-46s -> %-24s (%s)\n", $cmd, "[$out]", $why;
}
# and the exit status works exactly as Chapter 15.4 described
system(q{perl -e 'exit 3'});
printf "\nperl -e 'exit 3' -> exit status %d\n", $? >> 8;perl -e 'print "hello\n"' -> [hello] (the simplest form)
perl -e 'my $x = 6;' -e 'print $x*7, "\n"' -> [42] (two -e options, one program)
perl -E 'say "say needs -E"' -> [say needs -E] (-E switches on modern features)
perl -le 'print "l adds the newline"' -> [l adds the newline] (-l appends a newline to print)
perl -e 'print 2**10, "\n"' -> [1024] (any expression at all)
perl -e 'exit 3' -> exit status 3Two results from that worth naming:
Several -e options are joined into one program. The second row sets $x in the first -e and uses it in the second. Perl concatenates them with newlines between, so it is one script, not two. That is how you keep a slightly longer one-liner readable.
-E is -e plus modern features, which in practice means say. Plain perl -e 'say "x"' is a syntax error — String found where operator expected ... Do you need to predeclare say? — because say is a feature that must be enabled. Use -E and it works.
2. The Flags Worth Knowing
A handful of single letters do most of the work. They combine, so perl -lane is -l -a -n -e.
| Flag | Does |
|---|---|
-e | the program text follows |
-E | same, with modern features on (say) |
-l | strip the newline on input, add one to every print |
-n | wrap the program in a loop over every input line |
-p | the same loop, and print $_ at the end of each pass |
-a | split each line into @F |
-F | choose the separator -a splits on |
-i | edit the input files in place |
-w | warnings on |
-M | load a module, as in -MList::Util=sum |
-n, -p, -a, -F and -i get their own chapters next, because each has behaviour worth measuring. The two to understand now are -l and -M.
-l does two things at once. It chomps each input line, and it adds $/ — a newline — to everything print outputs. So perl -lne 'print length($_)' measures the line without its newline and prints the number on its own line. Without -l, the length is one larger and the numbers run together.
-M loads a module and can import from it:
perl -MList::Util=sum,max -lane 'push @s, $F[1]; END { print sum(@s), " ", max(@s) }' slack.txtList::Util is core, so that works anywhere. -MPOSIX, -MData::Dumper and -MFile::Basename are the other three you will reach for, all from Chapter 12.9's list.
3. Quoting: The Shell Reads It First
This is the only genuinely confusing part of one-liners, and it has nothing to do with Perl.
use strict;
use warnings;
# the SAME program text, quoted two ways for the shell
my $perl_program = 'my $x = "PERL"; print "x is [$x]\n"';
my $single = `perl -e '$perl_program' 2>&1`;
# build the double-quoted form the way a user would type it
my $dq = '"' . $perl_program . '"';
my $double = `perl -e $dq 2>&1`;
for ($single, $double) { s/\s+\z//; s/\n/ | /g }
print "the program text:\n $perl_program\n\n";
printf "in SINGLE quotes -> %s\n", "[$single]";
printf "in DOUBLE quotes -> %s\n", "[$double]";
print "\nthe shell expanded \$x before Perl saw it, so the program changed\n";the program text:
my $x = "PERL"; print "x is [$x]\n"
in SINGLE quotes -> [x is [PERL]]
in DOUBLE quotes -> [syntax error at -e line 1, near "my =" | Execution of -e aborted due to compilation errors.]
the shell expanded $x before Perl saw it, so the program changedThe same characters, two results. In double quotes the shell found $x, decided it was a shell variable, found it empty, and replaced it with nothing — handing Perl my = "PERL", which is not valid Perl at all.
That syntax error is the lucky outcome. It is loud, and you fix it immediately. The same expansion can just as easily produce a program that still compiles and quietly computes something else: perl -e "print $total" becomes print and prints $_, and perl -e "print 1 if $x > 5" becomes print 1 if > 5 — a different question with a believable answer. Chapter 14.1's third kind of failure, caused by a quote character.
The rules on a POSIX shell (sh, bash, zsh):
Single quotes pass everything through untouched. $, !, \, backticks — Perl receives exactly what you typed. This is what you want, essentially always.
Double quotes let the shell expand $name, backticks and \ before Perl sees them. Useful only when you deliberately want a shell value substituted into the program, which is rarely a good idea.
A single quote inside a single-quoted program needs care. You cannot escape it inside single quotes. The usual answer is to avoid apostrophes entirely, or close and reopen:
perl -e 'print "it'\''s awkward\n"' # close, escaped quote, reopen
perl -e "print \"it's easier\n\"" # or use double quotes deliberatelyBetter than either: when a program needs quotes of both kinds, that is the signal it has outgrown the command line.
4. When To Stop
A one-liner is the right tool for a job you will do once. The signals that you have passed that point:
You have typed it more than twice. Put it in a file. The third time is the one where you misremember a detail and get a wrong answer that looks right.
It needs more than two -e fragments, or any if you have to think about. Command lines have no indentation, no comments and no way to leave a note for the next person.
You want to keep the output. Something a colleague will read should come from a file you can point at, not from a shell history nobody else has.
It needs quotes of both kinds. As above — the escaping cost has exceeded the saving.
Promoting a one-liner to a file is mechanical. This:
perl -lane 'print "$F[0] $F[1]" if $F[1] < 0' slack.txtbecomes this, with the implicit parts written out:
#!/usr/bin/perl
use strict;
use warnings;
while (my $line = <>) { # what -n provided
chomp $line; # what -l provided
my @F = split ' ', $line; # what -a provided
next unless @F >= 2; # a check the one-liner could not afford
print "$F[0] $F[1]\n" if $F[1] < 0;
}Longer, and better in every way that matters once it is going to be run again: it has a name, it can be commented, it can check its input, and Chapter 15.3's validation can be added to it.
Chapter 15.7 writes out exactly what -n and -p expand to, using Perl's own deparser rather than a description — which makes the translation above something you can verify instead of trusting.
5. What To Remember
perl -e 'PROGRAM'runs a whole program with no file, and nothing is cut down.- Several
-eoptions join into one program. Measured:$xset in the first was used in the second. -Eenables modern features; plain-ewithsayis a syntax error — measured.-lchomps input and adds a newline to everyprint.-Mloads a module —-MList::Util=sum,maxand-MPOSIXare the common ones.-wwhile building, so a silently-zero value does not become an answer you trust.- Flags combine:
-laneis-l -a -n -e. - Single-quote the program. Measured: in double quotes the shell expanded
$xto nothing and Perl ran a different program. - Double quotes expand
$name, backticks and\before Perl sees them. - A
!in double quotes can trigger history expansion at an interactive prompt. - Forgetting the quotes makes Perl seem to hang — it is reading your terminal as a file.
- Stop at the third use, at two
-efragments, at any realif, or at needing both quote kinds. - Promotion is mechanical:
-nbecomes thewhileloop,-lbecomeschomp,-abecomessplit.
Chapter 15.7 takes the two flags that make one-liners genuinely powerful. -n and -p wrap your code in a reading loop, and Perl will show you the exact loop it generates.
Where this fits
Part of the Perl curriculum.
