Maori Farewell
This page explains the Maori Farewell trick, which gives you aBEGIN block inside a Perl one-liner. The butterfly operator handles cleanup at the end, but this trick handles setup at the start.
That's it. The-M5;
-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
The-M switch normally loads a Perl module:
But withperl -MJSON -e 'print encode_json({a=>1})'
-M5;, something different happens:
The command produces this output:perl -M'5;print "HELLO\n"' -ne 'print' file.txt
The print happens BEFORE the file processing starts. It acts as a pseudo-BEGIN block hiding inside theHELLO line 1 from file line 2 from file ...
-M switch.
Part 2: HOW IT WORKS
When Perl sees-M5;, it interprets this as:
The semicolon separates the version requirement from arbitrary code. Since we are all running Perl 5 or newer, the version check passes silently.use 5; # Require Perl version 5 (always true) print "..."; # Execute this code
What comes after the semicolon runs at compile time, before the -n or -p loop even starts. It is 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:The command produces this output:perl -M'5;print scalar localtime, "\n"' -ne 'print if /error/i' log.txt
The timestamp prints first, then matching lines follow.Wed Jan 5 15:30:45 2025 [15:30:46] ERROR: Database connection failed [15:31:02] ERROR: Invalid user input
Set a custom record separator:
This sets paragraph mode BEFORE the loop starts. Each "line" is now actually a paragraph (text between blank lines).perl -M'5;$/="\n\n"' -ne 'print if length > 100' document.txt
Initialize a counter with a starting value:
The command produces this output:perl -M'5;$n=100' -lne 'print $n++, ": $_"' file.txt
The counter starts at 100 instead of 0.100: first line 101: second line 102: third line
Part 4: WHY NOT JUST USE BEGIN?
You might think:And you would be right. That works too. But compare the character counts:perl -ne 'BEGIN { print "hello\n" } print' file.txt
In code golf, every character matters. The Maori Farewell saves two.-M'5;print "hi"' 17 characters 'BEGIN{print "hi"}' 19 characters
It also feels different because the initialization sits visually apart from the main loop code, which some find cleaner:
You can stack multipleperl -M'5;$/=undef' -M'5;$verbose=1' -ne '...'
-M flags, and each one handles one setup task. The command reads like a config file.
Part 5: VERSION FEATURES
Here is a bonus trick. You can use a real version number to enable language features:Theperl -M5.010 -E 'say "hello"'
-M5.010 flag enables Perl 5.10 features, including say. You can combine it with the semicolon trick:
You get both version features and initialization code in a single flag.perl -M'5.010;$count=0' -nE 'say ++$count, ": $_"' file.txt
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 does not work with module import lists:The# THIS FAILS: perl -M"List::Util=sum;print 'hi'" -e '...'
= syntax for selective imports breaks the trick. If you need module functions, load the module normally:
You use twoperl -MList::Util=sum -M'5;print "hi\n"' -e '...'
-M flags instead. One flag loads the module, and the second flag runs the farewell.
Part 7: COMBINING WITH BUTTERFLY
Now you have both ends covered:The command produces this output:perl -M'5;print "START\n"' -lne '$sum+=$_ }{ print "Sum: $sum"' nums.txt
The Maori Farewell handles the beginning. The butterfly operator handles the end. Your one-liner now has a proper setup and teardown.START Sum: 150
Part 8: THE ANNOTATED VERSION
Breaking it down:perl -M'5;print "START\n"' -lne '$sum += $_ }{ print "END: $sum"' file
You can chain three tricks into one command: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
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:Set environment variables before processing:perl -M'5;print "Line,Content\n"' -lne 'print "$.,\"$_\""' data.txt
Initialize complex data structures:perl -M'5;$ENV{DEBUG}=1' -ne '...' file.txt
That last example is a unique-lines-in-order filter with explicit initialization of the tracking structures.perl -M'5;%seen=();@order=()' -lne ' push @order, $_ unless $seen{$_}++; }{ print for @order ' file.txt
Part 10: THE NAME
Why "Maori Farewell"? It continues the cultural greeting theme:Both names reference traditional greetings from indigenous peoples. The Perl community has a habit of using whimsical names.}{ Eskimo greeting (two noses touching) -M5; Maori farewell (hongi - pressing foreheads)
Whether the cultural references are appropriate is debatable. The names stuck because they are memorable, and that matters for tribal knowledge passed between Perl hackers.
perl.gg.---. / \ | START | \ / '---' | V .-------. / LOOP \ \ -n -p / '-------' | V .---. / \ | END | \ / '---' Maori at the top, Butterfly at the bottom