The switches#
Every one-liner is a combination of a program (passed to -e or -E)
and a handful of switches that wrap implicit behaviour around it. This
chapter covers the switches you will reach for. Each one earns its
keep in the progression, regex, and numeric chapters that follow.
Readers coming from awk or sed already know what per-line
iteration, field splitting, and in-place editing look like; the
question is which pperl flag turns each on.
-e — run a program given on the command line#
pperl -e 'print "hello\n"'
-e takes the Perl source as its argument. Multiple -e chunks
concatenate; they behave as one program with semicolons between them.
pperl -e 'my $x = 41;' -e 'print $x + 1, "\n"' # 42
Use single quotes around the program so the shell leaves $_, $1,
\n, and backticks alone. See gotchas for what
goes wrong with double quotes.
-E — -e plus the modern feature set#
-E is -e with all optional features enabled: say,
state, fc, the // defined-or
operator, unicode string semantics under use feature 'unicode_strings',
and more.
pperl -E 'say "hello"' # instead of print "hello\n"
pperl -E 'say "pi = " . (atan2(1,1)*4)'
Reach for -E when writing new one-liners. Reach for -e only when
copy-paste compatibility with very old scripts matters.
-n — wrap an implicit read loop around the program#
-n turns the program into the body of a loop over every line of
every input file (or STDIN if none are given). The loop is exactly:
while (<>) {
# your program
}
$_ holds each input line, including its trailing newline. Nothing is
printed automatically — you decide what reaches STDOUT.
# Print lines containing "error"
pperl -ne 'print if /error/' app.log
Equivalent long form, shown once so the mechanical expansion is clear:
while (<>) {
print if /error/;
}
Every subsequent -n recipe in this guide relies on that expansion —
assume it without re-stating.
BEGIN { … } runs before the loop, END { … } runs after. Both are
ordinary Perl blocks and compose with -n cleanly.
# Count lines matching a pattern
pperl -ne '$n++ if /WARN/; END { print "$n\n" }' app.log
-p — like -n, but print $_ after each iteration#
pperl -pe 's/foo/bar/g' input.txt
Mechanical expansion:
while (<>) {
# your program
} continue {
print or die "-p destination: $!";
}
Reach for -p when the output is the (possibly modified) input.
Reach for -n when the output is a summary, a filtered subset, or
nothing at all.
-l — line-end handling#
-l does two things at once:
On input,
chompeach line as it is read under-n/-p.$_no longer ends in"\n".On output, set
$\(the output record separator) so everyprintappends"\n".
# Print just the first field of each tab-separated line
pperl -F'\t' -lane 'print $F[0]' table.tsv
Without -l, you would either write print "$F[0]\n" (the newline
moves into the program) or produce glued output.
-l accepts an optional octal argument that sets $\ to a different
character: -l012 keeps newline (the default), -l0 sets $\ to NUL,
and so on. The common use is the no-argument form.
-a — autosplit into @F#
Combined with -n or -p, -a splits $_ on whitespace and puts
the fields into @F. The default split is
split(' ', $_) — it trims leading
whitespace and treats any run of whitespace as one separator.
# Third column of every line
pperl -lane 'print $F[2]' data.txt
# Reverse column order
pperl -lane 'print "@{[reverse @F]}"' data.txt
@F is zero-indexed. $F[-1] is the last field. scalar @F is the
field count.
-F — change the split pattern#
-F sets the delimiter used by -a. The argument is a regex; a
literal comma is -F,, a colon is -F:, a tab is -F'\t'.
# Second field of a colon-separated file
pperl -F: -lane 'print $F[1]' /etc/passwd
# Split on any run of commas or semicolons
pperl -F'[,;]+' -lane 'print scalar @F' mixed.csv
-F implies nothing about -a; you still need -a. The common
idiom -F: -lane is colon-split, chomped, with @F available.
Quoting a tab requires a literal tab in the shell or the regex form:
pperl -F'\t' -lane 'print $F[0]' data.tsv # regex form, always safe
pperl -F' ' -lane 'print $F[0]' data.tsv # literal tab — fragile
-i — edit files in place#
-i rewrites the file pperl is reading from, replacing its
contents with whatever -p prints. The whole file’s output goes to a
temporary file; when the loop finishes, that temporary replaces the
original.
# Replace CRLF with LF in every .txt under cwd (no backup)
pperl -i -pe 's/\r\n/\n/g' *.txt
# Same, keeping a .bak copy beside each original
pperl -i.bak -pe 's/\r\n/\n/g' *.txt
Always use -i.bak (or another suffix) until you have verified
the edit against a representative file. A bug in the program with
bare -i destroys the input. See gotchas.
-i has no effect without -p (or explicit prints under -n): if
nothing is printed, the replacement file is empty.
-M and -m — load modules before the program runs#
-Mmodule is equivalent to use module; at the top of the program.
-Mmodule=sym1,sym2 is use module qw(sym1 sym2);.
pperl -MList::Util=sum -lane 'print sum @F' data.txt
pperl -MPOSIX=strftime -le 'print strftime("%F", localtime)'
pperl -MData::Dumper -e 'print Dumper({a=>1, b=>[2,3]})'
Lower-case -m is no strict … rather than use …; it is rarely
needed on the command line.
Modules most common in one-liners: List::Util (sum/min/max/uniq/any),
POSIX (strftime, mktime, fmod), Data::Dumper (inspect structures),
JSON::PP (parse/emit JSON), Text::CSV (quoted CSV),
MIME::Base64, Digest::MD5, Digest::SHA, Socket.
-0 — set the input record separator#
Perl normally reads a line at a time. -0NNN sets $/ to the
character with the given octal code, changing what “one record” means
for <>, <STDIN>,
and the -n / -p loop.
Common forms:
Form |
What |
Effect |
|---|---|---|
|
|
Read NUL-delimited records (matches |
|
|
Slurp the whole file as one record. |
|
|
Paragraph mode: blank lines separate records. |
|
|
Any single octal byte. |
# Count files from find -print0
find . -type f -print0 | pperl -0 -ne '$n++; END { print "$n\n" }'
# Slurp, then run a cross-line regex
pperl -0777 -ne 'print "yes\n" if /BEGIN.*?END/s' text.txt
# Print every paragraph containing "TODO"
pperl -00 -ne 'print if /TODO/' notes.txt
Paragraph mode (-00) interacts with -l: without -l, the blank
separator stays attached to each record; with -l, it is chomped.
-C — Unicode on stdio and/or @ARGV#
-C enables Unicode handling on specified streams. The argument is
either a number (bitmask) or a string of letters.
pperl -CSD -ne 'print' input.txt # stdin, stdout, stderr all UTF-8
pperl -CA -e 'print $ARGV[0]' äöü # @ARGV treated as UTF-8
pperl -CSA -nE 'say length' # S + A
Letter codes: I = stdin, O = stdout, E = stderr, S = I+O+E,
A = @ARGV, D = set default I/O layers (includes file opens).
For a fully UTF-8 session, -CSD. For one-off processing of named
UTF-8 files, -CSAD. See gotchas for the symptoms
that tell you -C is missing.
Reference table#
Every switch, its mechanical expansion, and the chapter where it first shows up in a recipe.
Switch |
Expands to |
First used in |
|---|---|---|
|
Run CODE as the program |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Auto-split |
|
|
Change |
|
|
Edit in place; with |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Enable Unicode on stdio, |
Special variables the switches set up#
Short catalogue; full definitions live in
perlvar.
Variable |
Role under |
|---|---|
|
The current input line (chomped if |
|
Current input line number (not reset between files by default). |
|
Input record separator. |
|
Output record separator appended by |
|
Output field separator inserted between |
|
Separator between array elements when interpolated in |
|
Auto-split fields under |
|
Remaining command-line arguments; filenames are consumed as processed. |
|
Name of the file currently being read ( |
Find out more#
progression applies every switch in recipes of increasing complexity.
perlvarlists every special variable pperl defines, not just the ones the switches touch.perlopcoversqr//, the flip-flop operator, and the diamond operator used by the-n/-ploops.