Skip to content
Files, Pipes, and Errors
step 1/5

Reading — step 1 of 5

Learn

~2 min readReal-World Perl

Real Perl scripts spend their time reading files, processing lines, and shelling out to other commands.

Reading file safely:

open(my $fh, '<', $path) or die "can't open $path: $!";
while (my $line = <$fh>) {
    chomp $line;
    process($line);
}
close $fh;

$! holds the last system error message. ALWAYS include it in die.

Slurp (read whole file):

open(my $fh, '<', $path) or die $!;
local $/;             # undef the line separator
my $contents = <$fh>;
close $fh;

or with a oneliner:

my $contents = do { local $/; open my $fh, '<', $path or die; <$fh> };

Writing:

open(my $out, '>', $path) or die "can't write $path: $!";
print $out "line 1\n";
print $out "line 2\n";
close $out;

Append: use >> instead of >.

Reading from a command (pipe in):

open(my $fh, '-|', 'ls', '-la') or die $!;
while (my $line = <$fh>) {
    print $line;
}
close $fh;

Writing to a command (pipe out):

open(my $mailer, '|-', 'sendmail', '-t') or die $!;
print $mailer "To: ada\@example.com\n";
print $mailer "Subject: hi\n\n";
print $mailer "hello\n";
close $mailer;

Backticks for capture-output one-shots:

my $output = `git status --porcelain`;
my @files = split /\n/, $output;

system — run command, return exit status, output goes to stdout/stderr:

system("ls /tmp") == 0 or die "ls failed: $?";

exec — replace current process with the command (no return on success).

die and warn:

die "fatal error\n";          # exits with non-zero
warn "non-fatal: $!\n";        # prints to stderr

If the message ends in \n, Perl uses it as-is. Otherwise it appends at <file> line <n>.

Exception handling with eval:

my $result = eval {
    risky_operation();
};
if ($@) {
    warn "failed: $@";
    $result = default_value();
}

eval { BLOCK } is Perl's try/catch. Errors caught into $@. Re-throw with die $@.

Try::Tiny (CPAN) provides modern try/catch:

use Try::Tiny;
try { risky() }
catch { warn "caught: $_" }
finally { cleanup() };

File tests:

-e $path        # exists
-f $path        # regular file
-d $path        # directory
-r $path        # readable
-w $path        # writable
-x $path        # executable
-s $path        # size > 0 (returns size)
-z $path        # size == 0
-M $path        # age in days since modification

-i in-place edit — Perl's killer feature for one-liners:

perl -i.bak -pe 's/foo/bar/g' files...

Rewrites files in-place, saves originals as .bak. The .tmp_run.sh of the Unix world.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…