How to tail -f a log file in Perl script?
Question
How to tail -f a log file in Perl script?
Tailing a Log File Like tail -f in Perl
The Unix command tail -f continuously monitors the end of a growing file, such as a log file. In Perl, you can replicate this behavior by reading from a filehandle, seeking to the file's end initially, and then waiting for new lines to be appended. This allows real-time monitoring directly within your Perl script without relying on external utilities.
Key Concepts
- Filehandle and seek: Open the file and move to the end so only new lines are read as they appear.
- EOF handling: When no new line is available, pause briefly, reset the EOF indicator using
seek, and retry. - Autoflush: Set
$| = 1to force immediate STDOUT output rather than buffered.
Perl Specific Notes
- Perl uses sigils like
$for scalars and<>angle brackets to read lines from a filehandle. seek($fh, 0, 1)is a classic Perl trick to clear EOF on a filehandle, enabling rereading as the file grows.- Perl's
$/, the input record separator, defaults to newline, so line-based reads work as expected.
Common Gotchas
- Make sure the file you tail exists and is readable to avoid errors.
- Infinite loops without a termination condition can hang your script—consider signal handling for real-world use.
- Log rotation requires extra logic, as the filehandle does not auto-update on file replacement.
Example: Demonstrating tail -f Pattern in Perl
This example demonstrates the core pattern for tailing a file. Since sandbox environments don't allow file I/O or infinite loops, this version simulates the technique by showing how new content would be detected and printed, with a bounded loop for demonstration purposes.
use strict;
use warnings;
# Simulate a log file as an in-memory array
my @log_lines = (
"Initial line 1\n",
"Initial line 2\n"
);
# Simulate file position (starting at end)
my $position = scalar @log_lines;
# Autoflush STDOUT
$| = 1;
print "Simulating tail -f behavior:\n";
print "Starting position: $position lines\n\n";
# Simulate new lines being appended to the log
push @log_lines, "New log entry at " . localtime() . "\n";
push @log_lines, "Another new entry\n";
push @log_lines, "Final entry for demo\n";
# Tail loop - check for new lines (limited iterations for sandbox)
for my $check (1..5) {
while ($position < scalar @log_lines) {
print $log_lines[$position];
$position++;
}
if ($position >= scalar @log_lines) {
print "[Check $check: No new lines, would sleep and retry...]\n";
}
last if $check == 3; # Exit after demonstrating the pattern
}
print "\nIn a real tail -f, this would loop indefinitely.\n";
Explanation
This script demonstrates the tail -f pattern without filesystem access:
- Uses an array to simulate log file contents that can grow over time.
- Tracks a position pointer, analogous to a file pointer after seeking to EOF.
- Checks for new entries beyond the current position and prints them.
- Shows the sleep-and-retry pattern when no new content is available.
- Uses bounded iteration to avoid timeout in sandbox environments.
Real Implementation Pattern
In production with actual files, you would use open, seek($fh, 0, 2) to jump to EOF, and seek($fh, 0, 1) to clear EOF status between read attempts. The core logic remains the same: continuously check for new content, print it immediately, and wait briefly when the end is reached.
Verified Code
Executed in a sandbox to capture real output. • v5.34.1 • 8ms
Simulating tail -f behavior:
Starting position: 2 lines
New log entry at Tue Dec 30 13:25:54 2025
Another new entry
Final entry for demo
[Check 1: No new lines, would sleep and retry...]
[Check 2: No new lines, would sleep and retry...]
[Check 3: No new lines, would sleep and retry...]
In a real tail -f, this would loop indefinitely.
(empty)