ZetCode

Perl special variables

last modified October 20, 2026

Perl has a large set of predefined variables that control the interpreter or expose information about the program and its environment. Many of them have punctuation names, such as $_ or $!, and are global. This article covers the ones used most often.

The default variable $_

The variable $_ is the default scalar. Many constructs set it implicitly and many functions use it when no argument is given: for, map, grep, print, length and pattern matches.

default_var.pl
#!/usr/bin/perl

use strict;
use warnings;
use v5.34.0;

my @words = qw(apple banana cherry);

for (@words) {
    say "word: $_";
}

my @lengths = map { length } @words;
say "lengths: @lengths";

my @long = grep { length > 5 } @words;
say "long: @long";

for (@words) {
    s/a/A/;
}
say "modified: @words";

The for loop without a loop variable aliases each element to $_. In map { length } @words the call to length has no argument, so it measures $_. Because $_ is an alias, the substitution s/a/A/ changes the elements of the original array.

$ perl default_var.pl
word: apple
word: banana
word: cherry
lengths: 5 6 6
long: banana cherry
modified: Apple bAnana cherry

Program name and arguments: $0 and @ARGV

The variable $0 holds the name of the running script and the array @ARGV holds the command-line arguments. Outside of subroutines, shift without an argument works on @ARGV.

args.pl
#!/usr/bin/perl

use strict;
use warnings;
use v5.34.0;

say "script: $0";
say "args:   ", scalar @ARGV;

for my $i (0 .. $#ARGV) {
    say "  ARGV[$i] = $ARGV[$i]";
}

my $first = shift;
say "first: ", $first // 'none';
say "left:  @ARGV";

The loop goes over the indexes 0 .. $#ARGV. The call to shift removes the first argument and returns it, and the defined-or operator // supplies a default when no arguments were passed. Inside a subroutine the same shift operates on @_ instead.

$ perl args.pl one two three
script: args.pl
args:   3
  ARGV[0] = one
  ARGV[1] = two
  ARGV[2] = three
first: one
left:  two three

Environment: %ENV

The hash %ENV contains the environment variables of the process. Changes to it are inherited by child processes started with system, backticks or exec.

env.pl
#!/usr/bin/perl

use strict;
use warnings;
use v5.34.0;

say "HOME: $ENV{HOME}";
say "missing: ", $ENV{NO_SUCH_VAR} // 'unset';

$ENV{GREETING} = 'hello';
system('echo "child sees: $GREETING"');

{
    local $ENV{GREETING} = 'temporary';
    system('echo "child sees: $GREETING"');
}

system('echo "child sees: $GREETING"');

Reading a missing key returns undef, so the defined-or operator gives a default. Setting $ENV{GREETING} makes the value visible to the shell started by system. With local the change is temporary and the previous value is restored at the end of the block.

$ perl env.pl
HOME: /home/jano
missing: unset
child sees: hello
child sees: temporary
child sees: hello

Errors: $! and $@

The variable $! holds the last system error. It is a dual-valued variable: in string context the message, in numeric context the errno number. The variable $@ holds the exception caught by eval, and is empty if no error occurred.

errors.pl
#!/usr/bin/perl

use strict;
use warnings;
use v5.34.0;

my $file = '/no/such/file.txt';

open(my $fh, '<', $file) or say "open failed: $!";

say "errno number: ", $! + 0;

eval { die "something went wrong\n" };
print "caught: $@" if $@;

eval { my $x = 1 / 0; };
print "caught: $@" if $@;

eval { 1 } and say "no error, \$@ is empty: '", $@, "'";

The failing open sets $! to the message No such file or directory, and adding zero to it gives the number 2. The die call inside eval stores its message in $@. Since the message ends with a newline, no location is appended; the division by zero error adds the file and line. A successful eval resets $@ to an empty string.

$ perl errors.pl
open failed: No such file or directory
errno number: 2
caught: something went wrong
caught: Illegal division by zero at errors.pl line 16.
no error, $@ is empty: ''

Output and process variables

A group of variables controls how output is formatted: $, is inserted between the arguments of print, $\ is appended at the end, $" separates the elements of an interpolated array, and $| turns on autoflush. Others describe the process: $$ is the process id, $^V the Perl version, $^O the operating system and $^T the start time.

output_vars.pl
#!/usr/bin/perl

use strict;
use warnings;
use v5.34.0;

my @a = (1, 2, 3);

{
    local $, = '-';
    local $\ = "!\n";
    print @a;
}

{
    local $" = ', ';
    say "list: @a";
}

{
    local $| = 1;
    say "autoflush: $|";
}

say "pid is numeric: ", ($$ =~ /^\d+$/ ? 'yes' : 'no');
say "perl version: $^V";
say "os: $^O";
say "program start is recent: ", (time - $^T < 5 ? 'yes' : 'no');
say "line: ", __LINE__, " file: ", __FILE__;

Each output variable is changed with local inside a block, so the old value comes back after the block. The first block prints 1-2-3! with a custom separator and terminator. The second one joins an interpolated array with a comma. The remaining lines read process information, together with the compile-time tokens __LINE__ and __FILE__.

$ perl output_vars.pl
1-2-3!
list: 1, 2, 3
autoflush: 1
pid is numeric: yes
perl version: v5.34.0
os: linux
program start is recent: yes
line: 29 file: output_vars.pl

Regex variables

After a successful match Perl sets the capture variables $1, $2 and so on, plus $& for the whole match, $` for the text before it and $' for the text after it. The arrays @- and @+ hold the start and end offsets of the match and of each group.

regex_vars.pl
#!/usr/bin/perl

use strict;
use warnings;
use v5.34.0;

my $s = 'Name: John Smith, age 42';

if ($s =~ /(\w+)\s+(\w+),\s+age\s+(\d+)/) {
    say "first: $1";
    say "last:  $2";
    say "age:   $3";
    say "match:  '$&'";
    say "before: '$`'";
    say "after:  '$''";
    say "whole match: $-[0] to $+[0]";
    say "group 2:     $-[2] to $+[2]";
}

The three groups capture the first name, last name and age. The match starts after the prefix Name: , which appears in $`, and the offsets $-[0] and $+[0] give the span of the whole match. Index 2 in the arrays refers to the second group. These variables are only valid until the next successful match in the same scope, so copy them if they are needed later.

$ perl regex_vars.pl
first: John
last:  Smith
age:   42
match:  'John Smith, age 42'
before: 'Name: '
after:  ''
whole match: 6 to 24
group 2:     11 to 16

Input variables: $. and $/

The variable $. is the line number of the last filehandle read. The variable $/ is the input record separator, a newline by default. Setting it to undef reads the whole file at once, and setting it to an empty string reads paragraphs.

input_vars.pl
#!/usr/bin/perl

use strict;
use warnings;
use v5.34.0;

my $text = "line1\nline2\n\nline4\nline5\n";

open(my $in, '<', \$text) or die $!;
while (<$in>) {
    chomp;
    say "$.: $_";
}
close $in;

my $slurp = do {
    local $/ = undef;
    open(my $fh, '<', \$text) or die $!;
    <$fh>;
};
say "slurped ", length $slurp, " characters";

my @paras = do {
    local $/ = '';
    open(my $fh, '<', \$text) or die $!;
    <$fh>;
};
say "paragraphs: ", scalar @paras;

The text is read through an in-memory filehandle, so no external file is needed. The loop prints each line prefixed with $.. The do blocks localize $/, so the change does not leak out: with undef the single read returns all 25 characters, and with an empty string the text is split into two paragraphs separated by the blank line.

$ perl input_vars.pl
1: line1
2: line2
3: 
4: line4
5: line5
slurped 25 characters
paragraphs: 2

Best Practices

In this article we have covered the most common Perl special variables: $_, $0, @ARGV, %ENV, $!, $@, the output and process variables, the regex match variables, and $. with $/.

Source

perlvar: Predefined Variables

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Perl tutorials.