Maori Farewell
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:
That's it. The -M switch, the number 5, and a semicolon. Everything after the semicolon runs before your main code.-M5;
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:But with -M5;, something different happens:perl -MJSON -e 'print encode_json({a=>1})'
Output:perl -M'5;print "HELLO\n"' -ne 'print' file.txt
The print happens BEFORE the file processing starts. It's a pseudo- BEGIN block hiding inside the -M switch.HELLO line 1 from file line 2 from file ...
Part 2: HOW IT WORKS
When Perl sees -M5;, it interprets this as:The semicolon separates the version requirement from arbitrary code. Since we're all running Perl 5+, 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'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: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. Now each "line" is 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:
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'd 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 - the initialization is visually separated from the main loop code, which some find cleaner:
Multiple -M flags, each doing one setup task. Reads like a config.perl -M'5;$/=undef' -M'5;$verbose=1' -ne '...'
Part 5: VERSION FEATURES
Here's a bonus trick. Use a real version number to enable features:The -M5.010 enables Perl 5.10 features, including say. Combine with the semicolon trick:perl -M5.010 -E 'say "hello"'
You get both: version features AND initialization code.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 doesn't work with module imports:The = syntax for selective imports breaks the trick. If you need module functions, load the module normally:# THIS FAILS: perl -M"List::Util=sum;print 'hi'" -e '...'
Two -M flags: one for the module, one for the farewell.perl -MList::Util=sum -M'5;print "hi\n"' -e '...'
Part 7: COMBINING WITH BUTTERFLY
Now you have both ends covered:Output:perl -M'5;print "START\n"' -lne '$sum+=$_ }{ print "Sum: $sum"' nums.txt
Maori Farewell at the beginning. Butterfly at the end. Your one-liner 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
Three tricks in 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 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 one 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 thing for whimsical naming.}{ Eskimo greeting (two noses touching) -M5; Maori farewell (hongi - pressing foreheads)
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