╔╦╗╔═╗╔═╗╦═╗╦ ╔═╗╔═╗╦═╗╔═╗╦ ╦╔═╗╦ ╦ ║║║╠═╣║ ║╠╦╝║ ╠╣ ╠═╣╠╦╝║╣ ║║║║╣ ║ ║ ╩ ╩╩ ╩╚═╝╩╚═╩ ╚ ╩ ╩╩╚═╚═╝╚╩╝╚═╝╩═╝╩═╝ ============================================================================ 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 ============================================================================ japh.codes