cv.cm

Coding · Programming languages

Perl tutorial for beginners

8 min read

Short answer

Perl is a dynamic scripting language created by Larry Wall in 1987, best known for text processing and powerful built-in regular expressions. It is preinstalled on most Unix systems and used for system administration, log processing and bioinformatics. This page covers running Perl, scalars, arrays and hashes, control flow, subroutines, references, regular expressions and error handling with die and eval.

Open Regex tester

What Perl is and what it is used for

Perl is a high-level, dynamically typed language created by Larry Wall in 1987. It was designed for text processing and report generation, and it became known as the glue language of Unix system administration and early web development. Perl's regular expressions were so influential that many other languages adopted a "Perl-compatible" regex syntax.

Today Perl is used for system administration scripts, log and text processing, bioinformatics, legacy web applications and one-line command-line filters. It is preinstalled on most Linux and Unix systems. CPAN, the Comprehensive Perl Archive Network, hosts a very large collection of reusable modules. This tutorial covers Perl 5; the language once called Perl 6 is now a separate language named Raku.

Run Hello, world

Check that Perl is installed with perl -v. On Windows, Strawberry Perl is a common distribution. Start every script with use strict; and use warnings;: they catch typos and unsafe code.

#!/usr/bin/env perl
use strict;
use warnings;

print "Hello, world!\n";
perl hello.pl
# Hello, world!
perl -e 'print "Hello from a one-liner\n"'

Statements end with a semicolon. Comments start with #. Double-quoted strings interpolate variables and escapes such as \n; single-quoted strings are literal.

Variables: scalars, arrays and hashes

Perl variables start with a sigil that shows the kind of value. Declare each variable with my, which makes it local to the enclosing block.

use strict;
use warnings;

my $name  = "Perl";             # scalar: one value
my $year  = 1987;
my @langs = ("Perl", "C", "sh"); # array: ordered list
my %port  = (http => 80, https => 443);  # hash: key-value pairs

print "$name since $year\n";    # Perl since 1987
print "First: $langs[0]\n";     # First: Perl (element is a scalar, so $)
print "Count: ", scalar(@langs), "\n";   # Count: 3
print "HTTPS: $port{https}\n";  # HTTPS: 443
print "Sum: ", "10" + 5, "\n";  # Sum: 15 (strings convert to numbers)
print "Join: " . "a" . "b" x 3, "\n";    # Join: abbb
SigilKindExample
$scalar: a number, string or referencemy $n = 42;
@array: an ordered list of scalarsmy @list = (1, 2);
%hash: unordered key-value pairsmy %h = (a => 1);
&subroutine (rarely written)&name

Control flow

Perl has if, elsif, else, unless, while, until, for and foreach. A short statement can be followed by a condition, which reads like English. next skips to the next iteration and last exits the loop.

use strict;
use warnings;

my $score = 72;
if ($score >= 90) {
    print "A\n";
} elsif ($score >= 70) {
    print "B\n";                 # B
} else {
    print "C\n";
}
print "passed\n" if $score >= 50;          # statement modifier
print "not perfect\n" unless $score == 100;

for my $i (1 .. 3) {
    print "i = $i\n";
}

my @names = ("ann", "bo");
foreach my $n (@names) {
    next if $n eq "bo";          # skip to the next item
    print ucfirst($n), "\n";     # Ann
}

my $k = 3;
while ($k > 0) { $k--; }

False values are 0, "0", the empty string "", the empty list and undef. Everything else is true.

Subroutines

Define a function with sub. Arguments arrive in the special array @_, and the usual first line copies them into named variables. A subroutine can return a scalar or a list.

use strict;
use warnings;

sub add {
    my ($x, $y) = @_;            # arguments arrive in @_
    return $x + $y;
}

sub greet {
    my ($name, $greeting) = @_;
    $greeting //= "Hello";       # default if undefined
    return "$greeting, $name!";
}

sub stats {
    my @nums = @_;
    my $sum = 0;
    $sum += $_ for @nums;
    return ($sum, $sum / @nums); # return a list
}

print add(2, 3), "\n";           # 5
print greet("Ann"), "\n";        # Hello, Ann!
my ($total, $avg) = stats(4, 8, 6);
print "$total $avg\n";           # 18 6

Modern Perl also supports signatures, as in sub add($x, $y) { ... }, enabled with use v5.36; or later, which also turns on strict and warnings.

Arrays, hashes and references

Arrays and hashes come with powerful built-in functions such as push, pop, shift, sort, map, grep, keys and exists. Nested data uses references: [ ... ] creates an array reference and { ... } a hash reference, and -> follows them.

use strict;
use warnings;

my @nums = (5, 3, 8, 1);
push @nums, 9;                           # add to the end
my $last = pop @nums;                    # remove from the end: 9
my @sorted  = sort { $a <=> $b } @nums;  # numeric sort
my @doubled = map  { $_ * 2 } @sorted;
my @big     = grep { $_ > 4 } @sorted;
print "@sorted | @doubled | @big\n";     # 1 3 5 8 | 2 6 10 16 | 5 8

my %age = (ann => 31, bo => 25);
$age{cy} = 40;
delete $age{bo};
for my $who (sort keys %age) {
    print "$who is $age{$who}\n";        # ann is 31 / cy is 40
}
print "has ann\n" if exists $age{ann};

# references build nested data structures
my $user = { name => "Ann", langs => ["Perl", "SQL"] };
print "$user->{name} knows $user->{langs}[1]\n";  # Ann knows SQL
print scalar @{ $user->{langs} }, "\n";           # 2

Inside a sort block, $a and $b are the two items being compared. <=> compares numerically and cmp compares as strings; plain sort @list sorts as strings, so 10 comes before 9.

Regular expressions

Regular expressions are built into Perl's syntax, which is its signature feature. =~ applies a match m/.../ or a substitution s/.../.../. Captured groups are available as $1, $2 and so on, and modifiers such as g (global) and i (case-insensitive) follow the closing slash.

use strict;
use warnings;

my $line = "2026-10-31 ERROR disk full on /dev/sda1";

if ($line =~ /^(\d{4})-(\d\d)-(\d\d)\s+(\w+)/) {
    print "year=$1 level=$4\n";          # year=2026 level=ERROR
}

(my $masked = $line) =~ s/\d/#/g;        # copy, then replace digits
print "$masked\n";                       # ####-##-## ERROR disk full on /dev/sda#

my @words = split /\s+/, $line;
print scalar(@words), " words\n";        # 6 words

my %h = ("a=1, b=2, c=3" =~ /(\w)=(\d)/g); # pairs into a hash
print join(",", map { "$_$h{$_}" } sort keys %h), "\n";  # a1,b2,c3

Use qr/.../ to store a compiled pattern in a variable, and the x modifier to write long patterns over several lines with comments.

Error handling

die raises an exception and warn prints a warning to standard error. eval { ... } catches an exception and puts the error message in $@. System calls such as open return false on failure and set $! to the operating system error, so check them with or die.

use strict;
use warnings;

sub divide {
    my ($x, $y) = @_;
    die "division by zero\n" if $y == 0;
    return $x / $y;
}

my $result = eval { divide(1, 0) };
if ($@) {
    print "Caught: $@";                  # Caught: division by zero
}

open(my $fh, "<", "missing.txt")
    or print "Cannot open: $!\n";        # Cannot open: No such file or directory

A die message that ends with \n is printed as written; without the newline, Perl appends the file name and line number. Since Perl 5.34 there is also an experimental try/catch feature, and modules such as Try::Tiny are widely used.

A small complete program: log level counter

This script reads a log from files named on the command line or from standard input, counts lines by level and prints a sorted summary. It shows the diamond operator <>, regular expressions, hashes and printf.

#!/usr/bin/env perl
# logstat.pl: count log levels in a file or standard input
use strict;
use warnings;

my %count;
my $lines = 0;

while (my $line = <>) {                  # reads files named on the command line, or STDIN
    chomp $line;
    $lines++;
    next unless $line =~ /\b(INFO|WARN|ERROR)\b/;
    $count{$1}++;
}

printf "%d lines read\n", $lines;
for my $level (sort { $count{$b} <=> $count{$a} || $a cmp $b } keys %count) {
    printf "%-5s %3d\n", $level, $count{$level};
}
perl logstat.pl app.log
# 120 lines read
# INFO   97
# WARN   18
# ERROR   5

Where to go next

  • perlintro and the other tutorials at perldoc.perl.org, also available offline with perldoc perlintro.
  • Learning Perl and Modern Perl, two well-known books for beginners.
  • MetaCPAN, the search interface for CPAN modules.
  • perlre and perlretut for the full regular expression reference.

FAQ

Is Perl still used?

Yes. Perl is preinstalled on most Unix-like systems and is still common in system administration, text processing, bioinformatics and long-running business systems, although fewer new web projects start in Perl.

What is the difference between Perl and Raku?

Raku began as Perl 6 but became a separate language with a different design. Perl 5 continues to be developed independently, and the name Perl refers to it.

Why do Perl variables start with $, @ and %?

The sigil shows what kind of value you get: $ for a single scalar, @ for a list and % for a hash. That is why one element of @items is written $items[0].

What does chomp do in Perl?

chomp removes a trailing newline from a string, which you usually need after reading a line from a file or the keyboard.

Is Perl good for regular expressions?

Yes. Regular expressions are part of Perl's core syntax, and PCRE, the regex library used by many other tools and languages, is named after Perl's regex style.

All coding tutorials