-n and -p are a loop¶
Level: 101 · you have run a one-liner and want to know what it did
One line: perl -ne 'CODE' file is while (defined($_ = readline ARGV)) { CODE }, and -p adds a continue block that prints $_ — which is why next inside -p skips nothing, and why $. keeps counting from one file into the next.
Perl's switches look like modes. They are source code. -n wraps the text of -e in a loop that reads every line of every file named on the command line — standard input, if none is named — into $_. -p is the same loop with a continue block that prints $_ after each pass. B::Deparse, loaded as -MO=Deparse, compiles a program and prints it back as Perl without running it, so the loop is something to read rather than something to remember.
Measured¶
The script runs each one-liner over demo/orders.txt, and asks Deparse what -n and -p turned into:
Verified output of n_and_p_loop_sh.sh — regenerated by tools/run_examples.py, never hand-typed.
$ cat orders.txt
1001 alice Kraków 12.50
1002 bob Warsaw 7.25
1003 alice Gdańsk 30.00
1004 carol Warsaw 4.75
$ perl -ne 'print if /Warsaw/' orders.txt
1002 bob Warsaw 7.25
1004 carol Warsaw 4.75
$ perl -MO=Deparse -ne 'print if /Warsaw/' 2>/dev/null
LINE: while (defined($_ = readline ARGV)) {
print $_ if /Warsaw/;
}
$ perl -pe 's/Warsaw/Warszawa/' orders.txt
1001 alice Kraków 12.50
1002 bob Warszawa 7.25
1003 alice Gdańsk 30.00
1004 carol Warszawa 4.75
$ perl -MO=Deparse -pe 's/Warsaw/Warszawa/' 2>/dev/null
LINE: while (defined($_ = readline ARGV)) {
s/Warsaw/Warszawa/;
}
continue {
die "-p destination: $!\n" unless print $_;
}
$ perl -pe 'next if /bob/' orders.txt
1001 alice Kraków 12.50
1002 bob Warsaw 7.25
1003 alice Gdańsk 30.00
1004 carol Warsaw 4.75
$ perl -ne 'next if /bob/; print' orders.txt
1001 alice Kraków 12.50
1003 alice Gdańsk 30.00
1004 carol Warsaw 4.75
$ perl -ne 'END { print "$. lines\n" }' orders.txt orders.txt
8 lines
$ perl -ne 'print "$ARGV $.\n" if eof; close ARGV if eof' orders.txt orders.txt
orders.txt 4
orders.txt 4
Reading what Deparse printed¶
LINE:— the loop has a label, sonext LINEandlast LINEwork even from inside a loop of your own.readline ARGV—ARGVis the filehandle behind<>. It opens each name in@ARGVin turn, reads standard input if there are none, and keeps the current file's name in$ARGV.continue { die "-p destination: $!\n" unless print $_; }— under-pthe print is not at the end of the loop body; it is in acontinueblock, which runs after every pass, including a pass that ended withnext. Soperl -pe 'next if /bob/'prints bob's line anyway. To leave a line out, use-nand print the lines you want, as the next command does. Thediemeans a failed write stops the one-liner instead of losing lines quietly.
$. does not start again¶
$. is the number of the last line read from the last filehandle read — and ARGV is one filehandle that moves from file to file without being closed. Named twice, orders.txt ends at line 8. Closing ARGV at each file's eof resets it, which is the last command: each file reports its own 4.
If you are coming from another language¶
- awk.
-nis awk's implicit loop over input lines, and-ain the next lesson is awk's field splitting. The encodings library shows why the awk on a Mac and the awk on Linux answer differently for the same non-ASCII file:awkis three programs ↗. - sed.
-pissed's habit of printing every line, and-nwith an explicitprintissed -nwithp. Seesedmatches patterns, not bytes ↗. - Python.
python3 -cruns its code once; there is no switch that writes the loop, so readingsys.stdinline by line is yours to write — see-cis not the prompt ↗, and Standard in, standard out, and pipes ↗ for what that loop costs.
See also¶
-l,-aand-Ftake a line apart — the lines those three switches add to this loop-iedits in place — where-p's print goes when the output is the file itself- perlrun ↗ — every switch, documented