perl.gg / one-liners

Maori Farewell

2024-07-07

The butterfly operator gives you an END block in one-liners. But what about BEGIN? What if you need code to run BEFORE the loop starts?

Enter the Maori Farewell:

-M5;
That's it. The -M switch, the number 5, and a semicolon. Everything after the semicolon runs before your main code.

Named for the Maori people of New Zealand (the pattern continues the cultural naming tradition of the Eskimo greeting). It exploits -M in a way the designers probably didn't intend.

Part 1: THE TRICK

Normally -M loads a module:
perl -MJSON -e 'print encode_json({a=>1})'
But with -M5;, something different happens:
perl -M'5;print "HELLO\n"' -ne 'print' file.txt
Output:
HELLO line 1 from file line 2 from file ...
The print happens BEFORE the file processing starts. It's a pseudo- BEGIN block hiding inside the -M switch.

Part 2: HOW IT WORKS

When Perl sees -M5;, it interprets this as:
use 5; # Require Perl version 5 (always true) print "..."; # Execute this code
The semicolon separates the version requirement from arbitrary code. Since we're all running Perl 5+, the version check passes silently.

What comes after the semicolon runs at compile time, before the -n or -p loop even starts. It's not quite a real BEGIN block, but it acts like one for practical purposes.

.--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/

Part 3: PRACTICAL EXAMPLES

Print a timestamp before processing:
perl -M'5;print scalar localtime, "\n"' -ne 'print if /error/i' log.txt
Output:
Wed Jan 5 15:30:45 2025 [15:30:46] ERROR: Database connection failed [15:31:02] ERROR: Invalid user input
The timestamp prints first, then matching lines follow.

Set a custom record separator:

perl -M'5;$/="\n\n"' -ne 'print if length > 100' document.txt
This sets paragraph mode BEFORE the loop starts. Now each "line" is actually a paragraph (text between blank lines).

Initialize a counter with a starting value:

perl -M'5;$n=100' -lne 'print $n++, ": $_"' file.txt
Output:
100: first line 101: second line 102: third line
The counter starts at 100 instead of 0.

Part 4: WHY NOT JUST USE BEGIN?

You might think:
perl -ne 'BEGIN { print "hello\n" } print' file.txt
And you'd be right. That works too. But compare the character counts:
-M'5;print "hi"' 17 characters 'BEGIN{print "hi"}' 19 characters
In code golf, every character matters. The Maori Farewell saves two.

It also feels different - the initialization is visually separated from the main loop code, which some find cleaner:

perl -M'5;$/=undef' -M'5;$verbose=1' -ne '...'
Multiple -M flags, each doing one setup task. Reads like a config.

Part 5: VERSION FEATURES

Here's a bonus trick. Use a real version number to enable features:
perl -M5.010 -E 'say "hello"'
The -M5.010 enables Perl 5.10 features, including say. Combine with the semicolon trick:
perl -M'5.010;$count=0' -nE 'say ++$count, ": $_"' file.txt
You get both: version features AND initialization code.

Common version features:

5.010 say, state, given/when 5.014 /r modifier for non-destructive substitution 5.016 __SUB__ for anonymous recursion 5.020 Postfix dereferencing

Part 6: LIMITATIONS

The Maori Farewell doesn't work with module imports:
# THIS FAILS: perl -M"List::Util=sum;print 'hi'" -e '...'
The = syntax for selective imports breaks the trick. If you need module functions, load the module normally:
perl -MList::Util=sum -M'5;print "hi\n"' -e '...'
Two -M flags: one for the module, one for the farewell.

Part 7: COMBINING WITH BUTTERFLY

Now you have both ends covered:
perl -M'5;print "START\n"' -lne '$sum+=$_ }{ print "Sum: $sum"' nums.txt
Output:
START Sum: 150
Maori Farewell at the beginning. Butterfly at the end. Your one-liner has a proper setup and teardown.

Part 8: THE ANNOTATED VERSION

perl -M'5;print "START\n"' -lne '$sum += $_ }{ print "END: $sum"' file
Breaking it down:
PIECE WHAT IT DOES ------------------------ ---------------------------------- perl Run Perl -M'5;print "START\n"' Maori Farewell: runs before loop -l Auto-chomp input, add newlines -n Wrap code in while(<>) loop -e '...' The main code $sum += $_ Loop body: accumulate sum }{ Butterfly: end loop, start end block print "END: $sum" End block: print final summary file Input file
Three tricks in one command:
1. Maori Farewell for setup 2. -n for implicit loop 3. Butterfly for cleanup

Part 9: REAL-WORLD USES

Print column headers before CSV processing:
perl -M'5;print "Line,Content\n"' -lne 'print "$.,\"$_\""' data.txt
Set environment before processing:
perl -M'5;$ENV{DEBUG}=1' -ne '...' file.txt
Initialize complex data structures:
perl -M'5;%seen=();@order=()' -lne ' push @order, $_ unless $seen{$_}++; }{ print for @order ' file.txt
That last one is a unique-lines-in-order filter with explicit initialization of the tracking structures.

Part 10: THE NAME

Why "Maori Farewell"? It continues the cultural greeting theme:
}{ Eskimo greeting (two noses touching) -M5; Maori farewell (hongi - pressing foreheads)
Both names reference traditional greetings from indigenous peoples. The Perl community has a thing for whimsical naming.

Whether the cultural references are appropriate is debatable. But the names stuck because they're memorable, and that's what matters for tribal knowledge passed between Perl hackers.

.---. / \ | START | \ / '---' | V .-------. / LOOP \ \ -n -p / '-------' | V .---. / \ | END | \ / '---' Maori at the top, Butterfly at the bottom

Created By: Wildcard Wizard. Copyright 2026