LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 3119 min read

Perl for System Administration

Build a practical sysadmin script that scans a directory, inspects file sizes and dates, and writes a backup-listing report.

Introduction

System administration is one of Perl's oldest and strongest use cases: quickly written scripts that inspect the filesystem, generate reports, and automate repetitive maintenance tasks. This lesson builds a small but realistic backup-listing script from the ground up.

What You Will Learn
  • How to list the contents of a directory.
  • How to read file size and modification time with stat.
  • How to filter files by size or age.
  • How to assemble those pieces into a working report-generating script.

Why Perl for Sysadmin Tasks

Perl ships by default on almost every Unix-like system, has direct, low-level access to filesystem and process functions, and lets you write a working script in a few lines instead of a few hundred. That combination made it the default automation language for system administrators for decades, and it is still common in that role today.

Scanning a Directory

opendir and readdir list the contents of a directory. readdir includes the special entries "." and ".." (the current and parent directory), which you almost always want to filter out.

use strict;
use warnings;
my $dir = '.';
opendir(my $dh, $dir) or die "Cannot open directory '$dir': $!\n";
my @files = grep { !/^\.\.?$/ } readdir($dh);
closedir $dh;
print "Found ", scalar(@files), " entries.\n";
print "$_\n" for @files;
Output (example directory contents)

Click Run to see what this code prints.

Getting File Metadata with stat

stat returns a fixed-length list of details about a file - permissions, owner, size, and three different timestamps. The two you will use most often are index 7 (size in bytes) and index 9 (last modification time, as a Unix epoch timestamp).

my @info = stat($filename);
my $size = $info[7];
my $mtime = $info[9];

Filtering Files by Size

Combining directory scanning with stat lets you filter for files matching a condition - for example, only regular files (using the -f file test) above a certain size.

use strict;
use warnings;
my $dir = '.';
opendir(my $dh, $dir) or die "Cannot open directory '$dir': $!\n";
my @files = grep { !/^\.\.?$/ && -f "$dir/$_" } readdir($dh);
closedir $dh;
for my $file (@files) {
my $path = "$dir/$file";
my @stat = stat($path);
my $size = $stat[7];
printf "%-30s %8d bytes\n", $file, $size if $size > 1_000;
}

Building a Backup-Listing Script

Putting it all together: a script that scans a directory, gathers size and last-modified date for every file, and writes a clean report to a new file - the kind of small utility a sysadmin might run before or after a backup job.

use strict;
use warnings;
my $dir = shift @ARGV // '.';
my $report_file = 'backup_report.txt';
opendir(my $dh, $dir) or die "Cannot open directory '$dir': $!\n";
my @files = grep { -f "$dir/$_" } readdir($dh);
closedir $dh;
open(my $out, '>', $report_file) or die "Cannot open '$report_file': $!\n";
printf $out "%-30s %12s %s\n", 'File', 'Size (bytes)', 'Modified';
for my $file (sort @files) {
my $path = "$dir/$file";
my @stat = stat($path);
my ($size, $mtime) = @stat[7, 9];
my @t = localtime($mtime);
my $date = sprintf('%04d-%02d-%02d', $t[5] + 1900, $t[4] + 1, $t[3]);
printf $out "%-30s %12d %s\n", $file, $size, $date;
}
close $out;
print "Backup report written to $report_file\n";
Output

Click Run to see what this code prints.

Common Mistakes

Avoid These Mistakes
  • Forgetting to filter out "." and ".." from readdir results.
  • Forgetting the -f file test and accidentally trying to stat or process directories as if they were files.
  • Using relative filenames from readdir without joining them back to the directory path.
  • Hardcoding stat's numeric indices everywhere instead of naming them, which hurts readability in larger scripts.
  • Assuming readdir returns entries in a useful order - it does not, so sort explicitly when order matters.

Best Practices

  • Always join a directory and filename explicitly, e.g. "$dir/$file", rather than assuming the current directory.
  • Check every open, opendir, and system call for failure and die with a clear message.
  • Consider the core module File::stat for named field access (like $st->size) instead of numeric indices.
  • Test scripts that touch the filesystem on a throwaway directory before pointing them at real data.
  • Sort file lists explicitly whenever the report needs a predictable order.

Frequently Asked Questions

-M returns a file's age in days since modification, -A since last access, and -C since the inode's status last changed - all relative to when the script started running.

No - the order is filesystem-dependent. Always sort explicitly if the order of your report matters.

Yes, particularly on systems where Perl is already installed by default and for maintaining existing Perl-based tooling, though many teams now also reach for Python for new scripts.

Key Takeaways

  • opendir/readdir/closedir list directory contents; always filter "." and "..".
  • stat returns size at index 7 and modification time at index 9.
  • The -f file test distinguishes regular files from directories and other entries.
  • Combining directory scanning, stat, and printf builds practical filesystem reports quickly.

Summary

Directory scanning and file metadata are the backbone of countless sysadmin scripts, from backup verification to disk-usage reports. Next, you will apply similar techniques to a different but equally common task: analyzing log files with regular expressions.

Next Lesson →

Perl for Text Processing