perl.gg / secret-operators

Double Diamond Operator

2026-01-07

The diamond operator has a problem. A security problem.
perl script.pl 'ls |'
That doesn't read a file called "ls |". It executes ls and reads its output. Oops.

Enter the double diamond:

<<>>
Same magic as <>. Without the danger.

Part 1: THE PROBLEM

The regular diamond uses two-argument open internally:
while (<>) # open(ARGV, $ARGV[0])
Two-argument open interprets magic characters:
|command Run command, read output command| Same thing >file Open for writing (!!) +<file Read-write mode
Filenames with these characters become attacks:
perl script.pl 'rm -rf /tmp/* |'
That's not a file read. That's command execution.

Part 2: THE FIX

Perl 5.22 introduced <<>>:
while (<<>>) { print; }
This uses three-argument open internally:
open(ARGV, '<', $ARGV[0])
The < forces read-only mode. Special characters become literal.
perl script.pl 'ls |' # Now reads file literally named "ls |" .--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/

Part 3: IDENTICAL BEHAVIOR

Everything else works the same:
while (<<>>) { print "$ARGV: $_"; }
Multiple files:
perl script.pl file1.txt file2.txt
STDIN fallback:
cat data.txt | perl script.pl
In-place editing with -i:
perl -i.bak -pe 's/old/new/g' *.txt
All the diamond magic, none of the risk.

Part 4: THE EDGE CASE

One exception: the explicit dash for STDIN.

Regular diamond:

perl script.pl file1.txt - file2.txt # Works: reads file1, STDIN, file2
Double diamond before Perl 5.28:
perl script.pl file1.txt - file2.txt # Error: Can't open - for reading
Fixed in 5.28. Now both handle - correctly.

Part 5: VERSION CHECK

Double diamond requires Perl 5.22+:
use v5.22; # Ensures <<>> is available while (<<>>) { # Safe input handling }
For older Perls, validate @ARGV manually:
for (@ARGV) { die "Invalid filename: $_" if /[|<>]/; } while (<>) { # Now safe-ish }

Part 6: IN ONE-LINERS

The -n and -p switches still use single diamond by default.

But you can use double diamond explicitly:

perl -e 'while (<<>>) { print if /pattern/ }' *.txt
Clunkier than -ne, but safer.

Or combine with validation:

perl -e 'die if grep /\|/, @ARGV; while (<>) { print }' *.txt

Part 7: WHEN TO USE WHICH

Use <<>> (double diamond) when:
- Filenames come from untrusted sources - Processing user-provided file lists - Building tools for others to use - Security matters
Use <> (single diamond) when:
- You control the input - Quick personal scripts - You need the pipe functionality intentionally - Backwards compatibility required

Part 8: INTENTIONAL PIPES

Sometimes the pipe behavior is desired:
@ARGV = ('sort -n data.txt |'); while (<>) { # Reads pre-sorted data }
This is a feature, not a bug. The single diamond supports it.

With double diamond, you'd need explicit pipe:

open my $fh, '-|', 'sort', '-n', 'data.txt'; while (<$fh>) { # Reads pre-sorted data }
More verbose, but explicit.

Part 9: PRACTICAL MIGRATION

Updating old scripts:
# Old way (insecure) while (<>) { process($_); } # New way (secure) while (<<>>) { process($_); }
One character change. That's it.

Part 10: THE NAME

Double diamond. Because there are two:
<<>>
Or "safe diamond." Or "three-argument diamond" (for how it works internally).

The community mostly calls it double diamond. Less confusion with the heredoc operator (which also uses <<).

Part 11: HEREDOC CONFUSION

Speaking of heredoc:
my $text = <<END; This is a heredoc. END
That's << followed by END. Not related to <<>>.

The double diamond is <<>> - two sets of angle brackets, nothing between them.

<<END # Heredoc <<>> # Double diamond
Context makes it clear. In a while condition, it's double diamond. With a word after <<, it's heredoc.

Part 12: SUMMARY

OPERATOR SAFE? PIPES? VERSION ---------------------------------------- <> No Yes All <<>> Yes No 5.22+
The double diamond is the diamond operator for the security-conscious era. Same functionality, without the footgun.

Unless you specifically need pipe expansion, use <<>>.

<<>> / \ << >> \ / \ / \/ SAFE Secure input since Perl 5.22

Created By: Wildcard Wizard. Copyright 2026