perl.gg / secret-operators

Double Diamond Operator

This page explains the double diamond operator in Perl and why you should prefer it over the single diamond for reading files. The single diamond operator has a security flaw where filenames containing shell metacharacters get executed as commands. The double diamond fixes this by forcing read-only mode.

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
perl.gg