do $filename will read the content of the file and the it will try to execute it insides the current process.

I use it sometimes when there is a command line program I'd like to test, but one that needs finer interaction than one could do if it was executed as an external Perl program. For example if I need to set some variables, or mock some part of the program.

Just as eval using do will also capture errors it encounters. It is important to understand how we can see those errors.

Here is how do reports problems.

Basically after calling do $filename;we need to check bot $! and $@ and verify that both are empty as either one of them can contain an error.

Let me show 3 scripts, the first one has no problems:

examples/do/code_works.pl

use strict;
use warnings;

print "Hello code_works\n";

This one has a compile-time error because of a missing my declaration.

examples/do/compile_time_error.pl

use strict;
use warnings;

print "Hello compile_time_error\n";
print $name;

This one is trying to load a module that does not exist:

examples/do/code_wrong_use.pl

use strict;
use warnings;

use MyModule;

print "Hello code_wrong_user\n";

The next one can run, but it has a run-time exception:

examples/do/code_exception.pl

use strict;
use warnings;

print "Before code_exception\n";

die "My Oups";

print "After code_exception\n";

Test script to check the cases

The following is a test script that check the $! and the <$@ in the various previous cases and also in a case where the do $filename; points to a file that does not exist.

examples/do/test_with_do.t

use strict;
use warnings;
use 5.010;

use Test::More;

# The return value of 'do' is whatever the last statement of the code.pl was.
# It can be undef as well even if everything is fine.

# $@ empty string if the  do was successful, the error message if it was not

subtest works => sub {
    do './code_works.pl';
    is $@, '';
    is $!, '';
};

subtest compile_time_error => sub {
    do './compile_time_error.pl';
    like $@, qr{Global symbol "\$name" requires explicit package name};
    is $!, '';
};

subtest code_with_wrong_use_statement => sub {
    do './code_wrong_use.pl';
    like $@, qr{Can't locate MyModule.pm};
    is $!, 'No such file or directory';
};

subtest code_with_runtime_exception => sub {
    do './code_exception.pl';
    like $@, qr{My Oups};
    is $!, '';
};

subtest do_no_such_file => sub {
    do './code_nope.pl';
    is $@, '';
    is $!, 'No such file or directory';
};


done_testing;

You can see that in all of the cases - expect the one with the working code - either $! or $@ and sometimes both had some content.

Documentation

See also the documentation of the do function.