ZetCode

Perl command line arguments

last modified October 8, 2026

In this article we work with command line arguments, environment variables, exit codes and options in Perl.

Scripts receive their command line arguments in the @ARGV array, the environment is exposed through the %ENV hash, and the script name is stored in $0. For option parsing, the core module Getopt::Long is available.

Perl @ARGV array

The first example prints the script name, the number of arguments, and the arguments themselves.

args.pl
#!/usr/bin/perl

use v5.34.0;
use warnings;

say "Script name: $0";
say "Number of arguments: ", scalar(@ARGV);
say "Arguments: @ARGV";

Arguments are stored in @ARGV as strings, in the order they were given. $0 holds the name of the script as it was invoked.

$ perl args.pl alpha beta "gamma delta"
Script name: args.pl
Number of arguments: 3
Arguments: alpha beta gamma delta

The quoted argument "gamma delta" is a single element of @ARGV, even though it contains a space. The shell removes the quotes before Perl sees the argument.

Perl shift in main program and in subroutines

The shift function removes the first element of an array. Without an argument, it works on @ARGV at the top level of the program, but on @_ inside a subroutine.

shift.pl
#!/usr/bin/perl

use v5.34.0;
use warnings;

sub inside_sub {

    my $arg = shift;
    say "Inside sub, shift returned: ", $arg // 'undef';
}

inside_sub();

say "ARGV still has: @ARGV";

my $first = shift;
say "Top-level shift returned: $first";
say "ARGV now has: @ARGV";

The subroutine is called without arguments, so its shift takes from the empty @_ and returns undef. The @ARGV array is not touched by that call.

my $first = shift;

At the top level, the same shift removes the first command line argument from @ARGV.

$ perl shift.pl one two
Inside sub, shift returned: undef
ARGV still has: one two
Top-level shift returned: one
ARGV now has: two

Counting and iterating over arguments

In the next example, we count the arguments with scalar(@ARGV) and loop over them by index and with foreach.

count.pl
#!/usr/bin/perl

use v5.34.0;
use warnings;

my $count = scalar(@ARGV);
say "Got $count argument(s)";

for my $i (0 .. $#ARGV) {

    say "Argument $i: $ARGV[$i]";
}

say "Iterating with foreach:";

foreach my $arg (@ARGV) {

    say "  $arg";
}

$#ARGV is the index of the last element, so 0 .. $#ARGV covers every index. When there are no arguments, $#ARGV is -1 and the loop body does not run.

$ perl count.pl red green blue
Got 3 argument(s)
Argument 0: red
Argument 1: green
Argument 2: blue
Iterating with foreach:
  red
  green
  blue

Perl %ENV environment variables

The %ENV hash gives access to the environment variables of the process. Reading a missing key returns undef, so we use the defined-or operator // to provide a default.

env.pl
#!/usr/bin/perl

use v5.34.0;
use warnings;

my $name = $ENV{GREETING_NAME} // 'Guest';
say "Hello, $name!";

say "GREETING_NAME is set: ", (exists $ENV{GREETING_NAME} ? 'yes' : 'no');

The program reads the GREETING_NAME variable. The exists check tells us whether the variable is present at all.

$ perl env.pl
Hello, Guest!
GREETING_NAME is set: no
$ GREETING_NAME=Alice perl env.pl
Hello, Alice!
GREETING_NAME is set: yes

In the second run, the shell sets the variable only for that single command.

Setting environment variables for child processes

Assigning to a key of %ENV changes the environment of the Perl process. Any child process started afterwards, such as one created by system, inherits the new value. The change does not affect the shell that started the script.

child.pl
#!/usr/bin/perl

use v5.34.0;
use warnings;

$| = 1;

$ENV{GREETING} = "Hello from Perl";

system('sh', '-c', 'echo "Child sees: $GREETING"');

say "Parent sees: $ENV{GREETING}";

We set GREETING in %ENV and then run a shell with system. The single quotes stop Perl from interpolating $GREETING, so the shell expands it instead. We set $| to 1 so that the output of the parent and the child appears in the right order.

system('sh', '-c', 'echo "Child sees: $GREETING"');

The list form of system runs sh directly, without going through an extra shell layer for Perl's quoting rules.

$ perl child.pl
Child sees: Hello from Perl
Parent sees: Hello from Perl

Perl exit codes

The exit function ends the program and returns a status code to the caller. By convention, 0 means success and any non-zero value means failure. This example validates its argument and uses different codes for different problems.

exit.pl
#!/usr/bin/perl

use v5.34.0;
use warnings;

my $file = shift @ARGV;

unless (defined $file) {

    say STDERR "Usage: $0 FILE";
    exit 2;
}

if (-e $file) {

    say "$file exists";
    exit 0;
}

say STDERR "$file does not exist";
exit 1;

Messages for the user go to STDERR, and the status is set with exit. Note that we use shift @ARGV explicitly here for clarity.

my $file = shift @ARGV;

We take the first argument, or undef when no argument is given.

$ perl exit.pl
Usage: exit.pl FILE
$ echo $?
2
$ perl exit.pl missing.txt
missing.txt does not exist
$ echo $?
1

The shell variable $? holds the exit status of the last command.

Perl Getopt::Long

Getopt::Long is a core module that parses options such as --verbose, --name=Alice or -c 3. Its GetOptions function stores the values in variables that we pass by reference. Each option specification ends with a type: no suffix for a flag, =s for a string, and =i for an integer.

options.pl
#!/usr/bin/perl

use v5.34.0;
use warnings;
use Getopt::Long;

my $verbose = 0;
my $name = 'World';
my $count = 1;

GetOptions(
    'verbose|v' => \$verbose,
    'name|n=s'  => \$name,
    'count|c=i' => \$count,
) or die "Error in command line arguments\n";

say "Verbose: ", $verbose ? 'yes' : 'no';
say "Name: $name";
say "Count: $count";

for (1 .. $count) {

    say "Hello, $name!";
}

say "Remaining arguments: @ARGV" if @ARGV;

The verbose|v specification is a flag that is set to 1 when given. The name|n=s and count|c=i options take a string and an integer. The vertical bar gives a long and a short name. After GetOptions removes the options it recognizes, the remaining arguments stay in @ARGV.

) or die "Error in command line arguments\n";

GetOptions returns false when it finds an invalid option, so we stop the program in that case.

$ perl options.pl --verbose --name=Alice -c 3 extra
Verbose: yes
Name: Alice
Count: 3
Hello, Alice!
Hello, Alice!
Hello, Alice!
Remaining arguments: extra
$ perl options.pl
Verbose: no
Name: World
Count: 1
Hello, World!

Getopt::Long with a hash of defaults

When GetOptions receives a hash reference as its first argument, it stores each option value under its name in that hash. This keeps the defaults and the parsed values in one place. The verbose|v! specification also accepts --no-verbose.

hash.pl
#!/usr/bin/perl

use v5.34.0;
use warnings;
use Getopt::Long;

my %opt = (
    name    => 'World',
    count   => 1,
    verbose => 0,
);

GetOptions(\%opt, 'name|n=s', 'count|c=i', 'verbose|v!')
    or die "Error in command line arguments\n";

for my $key (sort keys %opt) {

    say "$key: $opt{$key}";
}

The defaults are set before parsing. Any option given on the command line overwrites its default. Since the keys match the option names, we do not need separate variables.

$ perl hash.pl -c 2 -n Bob
count: 2
name: Bob
verbose: 0
$ perl hash.pl --no-verbose
count: 1
name: World
verbose: 0
$ perl hash.pl -v
count: 1
name: World
verbose: 1

In this article we have covered @ARGV, shift, $0, %ENV, exit codes and Getopt::Long in Perl.

Source

Getopt::Long documentation

Perl exit documentation

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.