🧑‍💻 agile sysadmin

by Ferenc Erki

Perl basics for Rex

Rex, the friendly automation framework does not expect much previous programming or Perl experience, though knowing a few foundational elements may go a long way.

While we provide a Just enough Perl for Rex page on our website, I often find myself sharing my own experience about getting started with Perl.

I decided to write my own take about the basics from a Rex perspective, and collect further resources I keep recommending or referring to.

Let’s see what I considered useful when I started out.

Documentation

Finding relevant information provides a solid foundation for learning effectively.

Read documentation

Perl provides the perldoc command to read documentation on the command line. For example perldoc perldoc shows its own documentation, and perldoc Rex shows the documentation of Rex.

To browse Perl’s own documentation online, I recommend either the Perldoc Browser or MetaCPAN. The latter also renders the documentation of all CPAN modules too, including Rex.

Write documentation

Perl has extensive documentation in the Plain Old Documentation (POD) format, which describes itself as:

a simple-to-use markup language used for writing documentation for Perl, Perl programs, and Perl modules.

No need to feel discouraged by either “plain” or “old” in its name, though – POD proves simple enough to even write books in it.

As a Perl project, Rex transparently supports documenting custom solutions in the POD format, and also uses POD for its own documentation.

=pod

=head1 Heading

Ordinary paragraph with B<bold> and I<italic> text,
as well as with C<inline code> and L<hyperlink|https://www.example.com>.

Command paragraphs treat the text specially and starts with “=”,
like “=pod” above.

 indent verbatim paragraphs
 for example for code blocks

=cut

Modules

Modules group together related functionality to reuse elsewhere. See perlmod as a reference.

Core modules

Perl itself comes with a set of modules to reuse common functionality between projects. Use the corelist command to find more information about the core modules.

For example to list all core modules coming with perl-5.40.1, use corelist -v 5.40.1 on the command line.

Import them with the use function:

use Time::Local; # import functionality from the Time::Local module

Other modules

The Comprehensive Perl Archive Network (CPAN) currently hosts the work from 14500+ authors in the form of 45000+ distributions containing 220000+ modules. Some of them likely solves the same problem one has to solve for their own use case.

The cpan client comes with Perl, while CPAN itself supports other clients too, like cpanm, and cpm.

Use the system package managers or one of those clients to install a distribution from CPAN locally, then reuse the modules:

use Rex; # imports the Rex module

Variables

Perl provides three built-in data types: scalars, arrays, and hashes.

See perldata as a reference.

I will use the values from the below examples throughout this post.

Naming

Perl calls the first character of a variable a sigil, denoting to the type of the data stored or accessed:

  • $ for scalars
  • @ for arrays
  • % for hashes

The variable name itself must begin with a letter or an underscore, and then may contain letters, underscores, and digits.

Scalars

A scalar represents a single value, like a number, a string, or a reference to other variables and objects.

my $name = 'Rex';       # a string
my $year = 2025;        # a number (integer)
my $pi   = 3.14;        # a number (float)
my $site = Site->new(); # an instance of a Site object

Arrays

An array represents an ordered list of scalars.

my @projects        = ( 'Rex', 'Perl' ); # list of two scalars, in that order
my @quoted_projects = qw( Rex Perl );    # qw() quotes the words

Use the index of an element to access it, starting the numbering from 0. Negative numbers count from the end.

my $first_project = $projects[0];  # Rex; note the $ sigil to access a scalar
my $last_project  = $projects[-1]; # Perl

Hashes

Hashes represent an unordered collection of key-value pairs.

my %site_for = (
    rex     => 'rexify.org', # the fat arrow autoquotes simple values on left
    'perl'  => 'perl.org',   # recommended trailing comma
);

Access values by the name of their associated keys.

my $rex_site  = $site_for{'rex'}; # rexify.org
my $perl_site = $site_for{perl};  # curly braces autoquote simple values too

References

A reference represents a scalar value that references something else: for example another scalar, an array, or a hash. Since arrays and hashes contain scalars, using references enable building complex data structures through nesting.

See perlref as a reference (pun intended 🙃), and perlreftut for “90% of the benefit with 10% of the details.”

Create references

Perl provides two main ways to create references:

my $ref_to_projects = \@projects;     # use \ in front to make a reference
my $ref_to_site_for = \%site_for;

my $projects_ref = [ 'Rex', 'Perl' ]; # note the square brackets for arrayrefs
my $site_for_ref = {
    rex  => 'rexify.org',             # note the curly brackets for hashrefs
    perl => 'perl.org',
};

Use references

Accordingly, Perl provides two ways to use references too, called dereferencing:

# using curly braces

my @project  = @{$projects_ref}; # dereference as an array
my %site_for = %{$site_for_ref}; # dereference as a hash

my $first_project = @{$projects_ref}[0];
my $perl_site     = %{$site_for_ref}{perl};

# using an arrow

my $last_project = $projects_ref->[-1];
my $rex_site     = $site_for_ref->{rex};

# postfix dereferencing with modern Perl

use v5.24; # use perl-5.24 features

my @project  = $projects_ref->@*;
my %site_for = $site_for_ref->%*;

Dump data structures

Perl comes with the Data::Dumper core module to stringify data structures.

use Data::Dumper;

print Dumper \@projects; # Dumper dumps scalars, hence the reference

# prints this:
$VAR1 = [
          'Rex',
          'Perl'
        ];

I also recommend using Data::Printer from CPAN for an improved experience:

use Data::Printer; # or use DDP as an alias

p @projects;       # recognizes the type of parameter on its own

# prints this:
[
    [0] "Rex",
    [1] "Perl",
]

Conditions

Make decisions based on comparing values.

Comparing strings

if ( $name eq 'Rex' ) { # condition to check; eq stands for equal
    print 'Hi Rex!';    # branch to execute when true
}

if ( $name ne 'FErki' ) { # ne stands for not equal
    print "Hi, $name!";   # double quotes interpolate $name, prints Hi Rex!
)
else {                    # optional branch to execute otherwise
    print 'You must be FErki!';
}

Comparing numerical values

if ( $year == 2025 ) {   # note the double = signs
    print 'this year';
}
elsif { $year < 2025 ) { # further condition in case previous didn’t match
    print 'in the past';
}
else {                   # optional branch to execute otherwise
    print 'in the future';
}

Regular expressions

See perlre as a reference, and perlretut as a tutorial to get started. If you already know about regular expressions, see also perlrequick for a quick start.

Matching

print 'match' if $name =~ m/Rex/;   # match due equivalence
print 'match' if $name =~ m/rex/;   # does not match due to lowercase r
print 'match' if $name =~ m/rex/i;  # match due to case insensitive matching
print 'match' if $name =~ qr{rex}i; # match, qr stands for quote like a regex

Loops

Iterate over data structures with a collection of values, like arrays and hashes.

foreach my $project (@projects) {
    print $project; # prints RexPerl
}

foreach my $project ( keys %site_for ) { # no guarantees about ordering
    my $site = $site_for{$project};      # $site gets set on each iteration
}

Loop control

Stop the loop or continue with the next element given a certain condition.

foreach my $project (@projects) {
    print $project;            # prints Rex
    last if $project eq 'Rex'; # stop the loop when condition matches
}

foreach my $project (@projects) {
    next if $project eq 'Rex'; # skip the rest of loop when condition matches
    print $project;            # prints Perl
}

Subroutines

Subroutines serve as user-defined functions.

sub greet_rex {
    print 'Hi Rex!';
}

greet_rex(); # prints Hi Rex!

Pass parameters

sub greet_user {
    my ($name) = @_;
    print "Hi $name!";
}

greet_user('FErki'); # prints Hi FErki!

Return results

sub get_this_year {
    return 2025;
}

my $current_year = get_this_year(); # 2025

Further resources

Due to Perl’s long history one may find a wide range of resources to learn from. I found the below ones valuable while I learned about Perl: