Diamond Operator
Two angle brackets. Empty:The diamond operator. Also called the null filehandle. Every Perl scripter uses it, often without knowing its name.<>
It reads from files or STDIN, magically.
Part 1: THE MAGIC
Run this script three ways:while (<>) { print; }
The diamond figures out what you meant. Files on command line? Read those. Nothing? Read STDIN. It just works.perl script.pl file1.txt file2.txt # Reads both files cat data.txt | perl script.pl # Reads from pipe perl script.pl # Reads from keyboard
Part 2: HOW IT WORKS
The diamond reads from @ARGV if it has files, otherwise from STDIN.Step by step:
It's the behavior that makes Unix filter programs work:1. Check @ARGV 2. If files exist, open and read the first one 3. When exhausted, move to the next file in @ARGV 4. If @ARGV is empty, read from STDIN
Same command, different input sources.grep pattern file.txt # Read from file cat file.txt | grep pattern # Read from pipe
.--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/
Part 3: THE -n AND -p SWITCHES
The diamond is why -n and -p work:This wraps your code in:perl -ne 'print if /pattern/' file.txt
The diamond handles the file automatically.while (<>) { print if /pattern/; }
Part 4: MULTIPLE FILES
Process many files seamlessly:$ARGV contains the current filename. The diamond reads each file in sequence.perl -ne 'print "$ARGV: $_"' *.txt
Output:
file1.txt: first line of file1 file1.txt: second line of file1 file2.txt: first line of file2 ...
Part 5: LINE NUMBERS
$. is the line number:But here's a gotcha: $. doesn't reset between files!while (<>) { print "$.: $_"; }
If file1.txt has 10 lines, file2.txt starts at line 11.perl -ne 'print "$.: $_"' file1.txt file2.txt
To reset, close ARGV explicitly:
while (<>) { print "$ARGV:$.: $_"; } continue { close ARGV if eof; # Reset $. for next file }
Part 6: MODIFYING @ARGV
You can manipulate @ARGV before the loop:Or add files programmatically:# Only process .log files @ARGV = grep { /\.log$/ } @ARGV; while (<>) { # ... }
Default to syslog if no files given.push @ARGV, '/var/log/syslog' unless @ARGV; while (<>) { # ... }
Part 7: THE DASH TRICK
A single dash means STDIN:This reads file1, then STDIN, then file2. Useful for mixing file input with piped data.perl script.pl file1.txt - file2.txt
echo "injected line" | perl script.pl before.txt - after.txt
Part 8: IN-PLACE EDITING
The diamond enables -i (in-place editing):This:perl -i.bak -pe 's/old/new/g' file.txt
The diamond is doing all the file handling.1. Reads file.txt via diamond 2. Processes each line 3. Writes back to the same file 4. Saves original as file.txt.bak
Part 9: READING ALL AT ONCE
Slurp mode reads entire file:Or multiple files into an array:local $/ = undef; # Unset record separator my $content = <>; # Read entire file(s)
Warning: memory-intensive for large files.my @all_lines = <>; # All lines from all files
Part 10: EXPLICIT FILEHANDLES
Diamond reads from ARGV implicitly. For explicit control:Or the old-school bareword:open my $fh, '<', 'file.txt' or die; while (<$fh>) { # ... }
Diamond is for when you want the magic.open FH, '<', 'file.txt' or die; while (<FH>) { # ... }
Part 11: THE SECURITY PROBLEM
Here's the dark side. The diamond uses two-argument open:Two-argument open interprets special characters:while (<>) # Internally: open(ARGV, $ARGV[0])
This doesn't read a file called "rm -rf / |". It EXECUTES that command and reads its output.perl script.pl 'rm -rf / |'
Dangerous if @ARGV comes from untrusted input.
Fix: use the double diamond (next tutorial) or validate @ARGV.
Part 12: USEFUL PATTERNS
Count lines in multiple files:Search and report with filenames:my $total = 0; while (<>) { $total++; } print "Total lines: $total\n";
Concatenate files with headers:while (<>) { print "$ARGV:$.: $_" if /pattern/; } continue { close ARGV if eof; }
my $current = ''; while (<>) { if ($ARGV ne $current) { print "=** $ARGV **=\n"; $current = $ARGV; } print; }
Part 13: THE NAME
Look at it:It's a diamond shape. Or an empty box. Or angle brackets with nothing inside.<>
"Null filehandle" is the technical name. "Diamond operator" is what everyone calls it.
The angles point outward like rays of magic, pulling input from wherever it needs to come from.
perl.gg<> / \ / \ < > \ / \ / \/ Magic input since Perl 1