Flip-flop Operator
This page explains how the.. operator changes behavior when Perl evaluates it in scalar context instead of list context. You already use it for number ranges, but it does something else entirely when you drop it into a while loop.
But in scalar context, it becomes something completely different:my @nums = (1 .. 5); # (1, 2, 3, 4, 5)
..
Output:while (<DATA>) { print if m~START~ .. m~END~; } __DATA__ ignore this START grab this and this END ignore this too
The flip-flop operator turns on when it hits the first pattern and turns off when it hits the second pattern. Every line between those two matches gets printed to your output.START grab this and this END
Part 1: THE TRICK
Part 2: HOW IT WORKS
The.. operator tracks two states while it scans a file. It stays off until the left condition matches, then it flips on and stays on until the right condition matches.
When the left side matches, it flips ON. When the right side matches, it flips OFF.OFF: Returns false, waiting for left condition to be true ON: Returns true, waiting for right condition to be true
It has MEMORY. Each call remembers the previous state.
.--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/
Part 3: THE STATES IN DETAIL
The important detail here is that both the starting line and the ending line appear in your output. The operator flips its state after it evaluates the current line.LINE LEFT RIGHT STATE OUTPUT -------------------------------------------------------- ignore false - OFF (skip) START TRUE false ON-> print (just turned on) grab false false ON print (still on) and this false false ON print (still on) END false TRUE ->OFF print (turning off now) ignore false - OFF (skip)
Part 4: LOG FILE PARSING
Extract a specific time range from logs:Grabs everything from 10:00 to 11:00.while (<$log>) { print if m~\[10:00:~ .. m~\[11:00:~; }
Extract a specific request:
Perfect for debugging specific transactions.while (<$log>) { print if m~BEGIN Request #1234~ .. m~END Request #1234~; }
Part 5: LINE NUMBER RANGES
Flip-flop works with line numbers too:Prints lines 3 through 7.while (<DATA>) { print if 3 .. 7; }
How? In scalar context, bare numbers compare against $. (the line number). So 3 .. 7 means "line 3 through line 7."
One-liner: print lines 5-10.perl -ne 'print if 5 .. 10' file.txt
Part 6: THE THREE-DOT VERSION
There's also...:
Difference: withwhile (<DATA>) { print if m~START~ ... m~END~; }
..., the right side isn't checked on the same line that triggered the left side.
Usually doesn't matter. But for edge cases:.. Two dots: left and right can match on same line ... Three dots: left and right can't match on same line
# Line says "START something END" m~START~ .. m~END~ # Flips on AND off on same line m~START~ ... m~END~ # Flips on, stays on until NEXT END
Part 7: MULTIPLE RANGES
The flip-flop resets when it turns off, so you can catch multiple ranges:Output:while (<DATA>) { print if m~BEGIN~ .. m~END~; } __DATA__ noise BEGIN first block END more noise BEGIN second block END final noise
Both blocks are captured.BEGIN first block END BEGIN second block END
Part 8: CONFIG FILE PARSING
Extract a section from a config:Fromwhile (<$config>) { print if m~\[database\]~ .. m~^\[~; }
[database] until the next [section].
Gotcha: this also prints the next section header. To exclude it:
Or process into a hash:while (<$config>) { if (m~\[database\]~ .. m~^\[~) { print unless m~^\[~ and not m~\[database\]~; } }
my %config; my $section; while (<$config>) { $section = $1 if m~^\[(\w+)\]~; $config{$section}{$1} = $2 if m~^(\w+)=(.*)~; }
Part 9: ONE-LINERS
Print between patterns:Print lines 10-20:perl -ne 'print if /START/ .. /END/' file.txt
Print from pattern to end of file:perl -ne 'print if 10 .. 20' file.txt
Print from start to pattern:perl -ne 'print if /START/ .. eof' file.txt
perl -ne 'print if 1 .. /END/' file.txt
Part 10: STATEFUL WARNING
The flip-flop has PERSISTENT state. This can bite you:If file1.txt ends without hitting END, the flip-flop stays ON for file2.txt.sub extract_section { my $file = shift; open my $fh, '<', $file or die; while (<$fh>) { print if m~START~ .. m~END~; } } extract_section('file1.txt'); extract_section('file2.txt'); # STATE CARRIES OVER!
Fix: reset state by reaching END, or use a different approach.
Part 11: THE NAME
Flip-flop comes from electronics. A flip-flop circuit has two stable states and switches between them based on input signals.Perl'sON ----+ +---- ON | | v v [TRIGGER] ^ ^ | | OFF ----+ +---- OFF
.. does the same thing: flips on with one condition, flops off with another.
Part 12: PRACTICAL EXAMPLE
Extract all function definitions from Perl code:From "sub name" to the closing brace.while (<$source>) { print if m~^sub \w+~ .. m~^}~; }
Extract error blocks from logs:
From ERROR to the next blank line (assuming stack traces are followed by blank lines).while (<$log>) { print if m~ERROR~ .. m~^$~; }
perl.gg.. / \ ON OFF \ / \/ [MEMORY] Stateful range matching since Perl 1