Home / Alt manpages / perldebtut(1)

  • perldebtut(1)
  • User command
  • linux

Debug Perl Scripts with strict, Warnings and the Built-in Debugger

You will finish with a repeatable Perl debugging routine: make the interpreter catch undeclared variables, inspect suspicious data, stop at a useful line, and step through a subroutine. The examples use Perl 5.38.2 and its built-in debugger on Linux. Allow 15 to 20 minutes, plus time to apply the same checks to your own script.

You need a shell and a Perl script that you can read. The debugger can execute Perl expressions at its prompt, so use it against code and data you trust. The commands below only read and run the example script; they do not need sudo.

1. Make the script fail early

Start with the checks that do not require an interactive debugger. use strict requires variables to be declared, while use warnings reports suspicious constructs at runtime. Put both near the top of a script:

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

my $name = 'Ada';
print "Hello, $name\n";

A declaration is part of the fix, not just a way to silence the error. Use my for a lexical variable whose scope should be limited to the current block or file, and investigate before reaching for a package variable.

For a syntax-only check, run:

$ perl -c /path/to/script.pl
/path/to/script.pl syntax OK

The check compiles the file but does not run its normal work. If you see a message such as Global symbol "$name" requires explicit package name, declare the variable or correct its spelling before continuing.

Checkpoint

Do not start interactive debugging until perl -c reports syntax OK. A debugger session is much easier to read when compilation errors are already gone.

2. Use warnings to expose data mistakes

Warnings are particularly useful when the code compiles but the result is wrong. This small hash has an odd number of values because and jerry is accidentally two words:

use strict;
use warnings;

my %data = (
    'tom' => qw(and jerry),
);
print $data{'tom'};

Run it with the warning switch while you are investigating an older script that does not yet enable warnings itself:

$ perl -w /path/to/script.pl
Odd number of elements in hash assignment at /path/to/script.pl line 5.

The line number can differ. It identifies the assignment that deserves inspection, not necessarily the first place where the bad value becomes visible. In this example, quote the phrase as one value:

my %data = (
    'tom' => q(and jerry),
);

Prefer use warnings in maintained code, because the setting is visible in the file and travels with the script. Keep -w in mind for a quick check of a script you are not ready to edit.

3. Start the built-in debugger safely

When compilation and warnings have not explained the behaviour, add -d to the normal command:

$ perl -d /path/to/script.pl
Loading DB routines from perl5db.pl version 1.77
Editor support available.

Enter h or 'h h' for help, or 'man perldebug' for more help.
main::(/path/to/script.pl:5):
5:    my %data = (welcome => 'Hello World');
  DB<1>

The exact banner and line number depend on the installed Perl and script. On this machine Perl 5.38.2 loads debugger routines version 1.77. The prompt means execution is paused before the displayed executable line.

Quit with the single debugger command q. Do not type quit or exit as debugger commands:

DB<1> q
$

Checkpoint

If the session is waiting at DB<N>, the debugger is running. If you are back at your shell prompt, it has ended. This distinction prevents you from typing debugger commands into the shell, where they may become unrelated commands or errors.

4. See the code and advance one statement

Start another session and use v to view source around the current line. A lone period, ., returns to the current line when your view has moved elsewhere. Use l 12 to list a particular line:

DB<1> v
DB<2> l 12

The debugger marks the next line to execute with an arrow. It has not run yet, so a variable assigned on that line may still be undefined. Press s to single-step, including into a subroutine. Press n to execute the next statement but step over a subroutine call.

After stepping past an assignment, print a scalar or expression with p:

DB<3> s
DB<4> p $key
welcome

p uses the script's current package and prints a scalar result. You can evaluate an expression too, so compare a suspect calculation without editing the file. Treat that ability as code execution, not as a read-only inspection feature.

5. Stop at a line or subroutine

Single-stepping from the first line is noisy for a larger program. Set a breakpoint with b, then continue with c:

DB<5> b 18
DB<6> c
main::(/path/to/script.pl:18):    print "$result\n";

Replace 18 with a real line number in your file. You can also continue to a named subroutine:

DB<7> c calculate_total

Use L to list breakpoints and watches, and B 18 to delete the breakpoint at line 18. A breakpoint does not edit the script or persist after the debugger session ends.

At a breakpoint, use r to return from the current subroutine. The debugger reports the scalar return value when it stops. Use T for a stack trace if the current call path is unclear.

6. Inspect hashes, arrays and nested data

Printing a hash directly can flatten its keys and values into an unreadable string. The debugger's x command dumps a value in a structured form. Pass a reference when you want the hash structure preserved:

DB<8> x \%data
0  HASH(...)
   'tom' => 'and jerry'
   'welcome' => 'Hello World'

The memory address and hash order vary, so do not compare the whole dump as fixed output. Look for the keys, values and nesting that matter to the bug. For an array, use x \@items. For an object or nested reference, x $object can show the contained structure.

If the value is not what you expected, check the expression that built it rather than changing it at the prompt and forgetting that the change is temporary. Prompt assignments are useful experiments; they are not a correction to the source file.

7. Apply the debugger's answer to the source

Use the smallest verified change that explains the observed value. For example, if a Fahrenheit-to-Celsius calculation contains:

my $c = 5 * $f - 32 / 9;

the debugger can compare candidate expressions against the current $f. The corrected formula is:

my $c = 5 * ($f - 32) / 9;

Exit with q, edit the actual file, then repeat both checks:

$ perl -c /path/to/script.pl
/path/to/script.pl syntax OK
$ perl -w /path/to/script.pl INPUT_VALUE

Keep the original input and script until the normal run produces the expected result. The debugger does not make a backup, and edits made to the file while a process is running do not retroactively change the already loaded code.

Done means

  • use strict and use warnings are present, or you have a clear reason they are not.
  • perl -c reports syntax OK.
  • The warning output is understood rather than hidden with a broad suppression.
  • You can start with perl -d, inspect with p or x, step with s or n, and stop with q.
  • The corrected script passes the same checks and produces the expected output on representative input.