<!-- category: secret-operators -->
The Eskimo Greeting }{
Count the lines in a file:Four characters do the work:perl -lne '}{ print $.'
}{
The Eskimo Greeting. Named because it looks like two people rubbing noses, Inuit style. One of Perl's "secret operators," a syntactic accident that turns out to be ridiculously useful in one-liners.
Those two braces break out of the implicit while loop that -n
creates, and start a new block that runs exactly once, after all
input has been processed. An END block without typing END.
Part 1: WHAT -n AND -p DO
When you write:Perl wraps your code like this:perl -ne 'CODE'
Every line of input becomeswhile (<>) { CODE }
$_, your code runs, next line. The
-p flag does the same thing but adds print at the end of each
iteration.
Simple enough. But what if you want to do something AFTER all lines are processed? Print a total. Show a summary. Output the final state of some accumulator.
You could use an END block:
Or you could use two braces and save yourself some typing.perl -ne '$sum += $_; END { print $sum }' numbers.txt
Part 2: HOW }{ WORKS
Perl wraps it into:perl -ne '$sum += $_; }{ print $sum' numbers.txt
Thewhile (<>) { $sum += $_; } { print $sum }
} closes the while loop. The { opens a bare block. That bare
block runs once, after the loop finishes. Your summary code goes
there.
It's not a real operator. It's just how Perl's syntax shakes out when you jam a closing brace against an opening brace inside}{ / \ } { / \ close open while bare loop block Two Inuit, nose to nose
-n's
implicit loop. A happy accident of grammar.
Part 3: LINE COUNTING
The simplest use. Count lines in a file:perl -lne '}{ print $.' file.txt
$. is Perl's line counter. It auto-increments with every line
read. After the Eskimo Greeting, the while loop is done, and $.
holds the final count.
No code in the loop body at all. The -n loop just reads and
discards every line. The }{ skips to the end where we print.
Equivalent to wc -l, but in Perl.
Part 4: SUMMING AND AVERAGING
Add up numbers, one per line:The loop body accumulates. The Eskimo block prints the total.perl -lne '$s += $_; }{ print $s' numbers.txt
Average:
perl -lne '$s += $_; }{ print $s / $.' numbers.txt
$s is the sum, $. is the count. Divide after all input is
consumed. You can't compute the average until you've seen every
value, which is exactly what }{ gives you.
Min and max:
perl -lne ' $min = $_ if !defined $min || $_ < $min; $max = $_ if !defined $max || $_ > $max; }{ print "min=$min max=$max" ' numbers.txt
Part 5: COMBINING WITH BEGIN
You can useBEGIN blocks in one-liners too. Now you have setup,
loop, and teardown:
Which Perl wraps into:perl -lne ' BEGIN { print "Starting analysis..." } $total += $_; $count++; }{ printf "Lines: %d Sum: %d Avg: %.2f\n", $count, $total, $total / $count ' numbers.txt
Three phases. One command. No script file needed.BEGIN { print "Starting analysis..." } while (<>) { $total += $_; $count++; } { printf "Lines: %d Sum: %d Avg: %.2f\n", $count, $total, $total / $count; }
Part 6: WORD FREQUENCY AND LOG ANALYSIS
Count every word in a file, sorted by frequency:The loop body splits each line into words and counts them in a hash. The Eskimo block sorts by frequency and prints. A full word-frequency analyzer in one command.perl -lne ' $w{lc $_}++ for split m~\W+~; }{ printf "%6d %s\n", $w{$_}, $_ for sort { $w{$b} <=> $w{$a} } keys %w ' book.txt
IP address frequency from an access log:
Error and warning counts:perl -lne ' if (m~(\d+\.\d+\.\d+\.\d+)~) { $ip{$1}++ } }{ printf "%6d %s\n", $ip{$_}, $_ for sort { $ip{$b} <=> $ip{$a} } keys %ip ' access.log
The loop extracts. The Eskimo block reports. Clean separation.perl -lne ' $err++ if m~ERROR~; $warn++ if m~WARN~; }{ print "Errors: $err, Warnings: $warn" ' app.log
Part 7: MULTIPLE ACCUMULATORS
You're not limited to one variable. Build as many accumulators as you need:A fullperl -lne ' $lines++; $words += scalar split m~\s+~; $chars += length; }{ printf "lines: %d words: %d chars: %d\n", $lines, $words, $chars ' file.txt
wc clone. Lines, words, and characters.
HTTP status code breakdown:
Four counters, one pass, one report.perl -lne ' m~^(\d{3})~ && $code{$1}++; }{ printf "%s: %d\n", $_, $code{$_} for sort keys %code ' status_codes.txt
Part 8: WITH -p (AND WHY YOU PROBABLY WANT -n)
The-p flag adds a print after your code. With }{:
Becomes:perl -pe '}{ print "--- END ---\n"'
That implicitwhile (<>) { # (empty, nothing before }{) } { print "--- END ---\n"; print; # the implicit print from -p }
print still fires in the Eskimo block. And $_ is
whatever it was last set to. Surprise.
Usually you want -n, not -p, when using }{. With -n, there's
no ghost print at the end.
Part 9: GOTCHAS
Variables don't reset between files.If you pass multiple files:
You get the total across both files. Theperl -lne '$c++; }{ print $c' file1.txt file2.txt
}{ block runs once, after
ALL input from ALL files. For per-file summaries, use eof instead:
Theperl -lne '$c++; if (eof) { print "$ARGV: $c"; $c = 0 }' file1.txt file2.txt
eof function (without parens) returns true at the end of each
file. Per-file hooks without the Eskimo.
$. counts across files too. After reading file1.txt (10 lines)
and file2.txt (5 lines), $. is 15. Track per-file counts manually.
Empty input still runs the Eskimo block.
No input lines, but the post-loop block executes. Accumulators areecho -n | perl -lne '$c++; }{ print "count: ", $c // 0'
undef unless initialized. The // 0 handles it with defined-or.
.--. |o_o | "Two noses, one result." |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/
Part 10: }{ VS END BLOCK AND THE NAME
Both run code after all input. The differences are subtle.END blocks run during interpreter shutdown. Global destruction may have started. Objects might be partially destroyed.
}{ runs as regular code after the loop. Everything is still alive.
No destruction. For one-liners with objects or tied variables, }{
is the safer choice.
As for the name: Eskimo Greeting. Two Inuit people touching noses.
Tilt your head. The}{ } { \ / \ / \/ nose touch
} is one person facing right. The { is
another facing left. They meet in the middle, noses touching. The
name comes from Philippe Bruhat (BooK) and the Perl secret operators
list. Same crew that named the goatse operator, the spaceship, and
the Venus. Perl hackers have a talent for naming things.
Whatever you call it, two braces that turn any accumulating one-liner into a proper extract-and-report pipeline.
perl.gg}{ / \ ____/ \____ / \ / \ | LOOP | | POST | | | | | | body | | code | \____/ \____/ End the loop. Begin the summary.