do#
Execute a block of code or run a Perl source file as if it were part of the current program.
do wears two unrelated hats that share only a keyword. do BLOCK groups statements into a single expression and returns the value of the last one - a syntactic tool, not a function. do EXPR treats the string as a filename and compiles-and-runs the file at runtime. Read whichever section matches the form you see; mixing them up is the most common source of confusion around this keyword.
Synopsis#
do BLOCK # group statements, yield last value
do EXPR # load and run a Perl file
do { ... } while CONDITION; # post-test loop idiom
What you get back#
do BLOCK - group statements into one expression#
do BLOCK is not a function. It is a syntactic construct that turns a brace-delimited sequence of statements into a single term whose value is the value of the last statement. Reach for it when the language wants an expression but you have several statements to run:
my $x = do {
my $tmp = fetch_raw();
$tmp =~ s/\s+\z//;
lc $tmp;
}; # $x = cleaned, lower-cased value
When do BLOCK is modified by a trailing while or until, the block runs once before the condition is tested - this is the standard post-test loop idiom:
do {
$line = <$fh>;
} while defined $line && $line !~ /^END\b/;
On any other statement, while and until as statement modifiers test the condition first. do is the exception.
next, last, redo do not work inside do BLOCK#
A do BLOCK is not a loop, even when trailed by while or until. Loop-control keywords do not see it:
do {
last if $done; # WRONG - not a loop
} while $more;
If you need loop control, wrap the body in a bare block, which is a loopable scope:
{
last if $done;
redo if $retry;
}
Or use an explicit while loop.
return inside a bare do BLOCK#
return in a do BLOCK returns from the enclosing subroutine, not from the block itself. That is occasionally what you want and occasionally a bug - either way, know which one you are writing:
sub classify {
my $n = shift;
my $kind = do {
return "zero" if $n == 0; # returns from classify(), not the do
$n > 0 ? "pos" : "neg";
};
"$kind ($n)";
}
To yield a value from the block without returning from the sub, just let the last expression be the value - that is the whole point of do BLOCK.
do EXPR - load and run a Perl source file#
do EXPR evaluates EXPR, treats the result as a filename, reads the file, compiles it, and runs it in the current package. It is similar to, but not quite the same as,
eval `cat stat.pl`;
The do form runs no external process, keeps the original filename for error messages, and cannot see lexicals in the enclosing scope - which eval STRING can. Like eval STRING, the file is reparsed on every call, so do FILE inside a loop is almost always wrong.
Path resolution and @INC#
The filename is interpreted like this:
Absolute paths (
/foo/stat.pl), paths beginning with./, and paths beginning with../are used as-is.Any other relative path is searched along
@INC, and on success the found path is recorded in%INCunder the key you passed.
do '/etc/myapp/stat.pl'; # exact file
do './stat.pl'; # exact file, current directory
do 'stat.pl'; # search @INC
do 'MyApp/config.pl'; # search @INC
Since Perl 5.26 . is not in @INC by default, so a bare do 'stat.pl' no longer falls back to the current directory. If the file is not found, Perl emits the hint:
do "stat.pl" failed, '.' is no longer in @INC;
did you mean do "./stat.pl"?
Pass ./stat.pl when you mean the current directory.
Return value and error reporting#
do EXPR has three outcomes you must distinguish:
Outcome | Return | ||
|---|---|---|---|
File compiled and ran | value of last expression |
| unchanged |
File read but did not compile | compile error | may also be set | |
File could not be read |
| I/O error |
Because compilation failure can incidentally set $! as well, always check $@ first:
my $return;
for my $file ("/etc/myapp.rc", "$ENV{HOME}/.myapprc") {
unless ($return = do $file) {
warn "couldn't parse $file: $@" if $@;
warn "couldn't do $file: $!" unless defined $return;
warn "couldn't run $file" unless $return;
}
}
The three warns correspond to the three failure shapes above plus the fourth case - the file ran but its last expression was false.
Why not use do FILE for modules#
For loading library code, use require or use instead of do EXPR. require caches through %INC (so a file is loaded at most once), raises an exception on failure instead of returning undef, and integrates with @INC hooks. use adds compile-time loading and import handling on top. do EXPR exists for configuration files and ad-hoc script inclusion - not for libraries.
Examples#
Group statements into an expression:
my $config = do {
open my $fh, "<", $path or die $!;
local $/;
<$fh>;
}; # $config = whole file as one string
Post-test loop with do … while:
my $n;
do {
print "enter a positive number: ";
chomp($n = <STDIN>);
} until defined $n && $n =~ /\A\d+\z/ && $n > 0;
Read a Perl-syntax configuration file, with full three-way error handling:
my $cfg = do '/etc/myapp/config.pl';
if (!defined $cfg) {
die $@ ? "config parse error: $@"
: "config read error: $!";
}
die "config did not return a true value" unless $cfg;
Conditional value selection where each branch is several statements:
my $greeting = do {
if ($user) {
my $name = $user->display_name;
"hello, $name";
}
else {
"hello, stranger";
}
};
Temporary localisation that must span several statements and still yield a value:
my $dump = do {
local $Data::Dumper::Sortkeys = 1;
local $Data::Dumper::Indent = 1;
Data::Dumper::Dumper(\%state);
};
Global state it touches#
@INC- searched whendo EXPRis called with a relative path other than./…or../….%INC- updated with the resolved path whendo EXPRsucceeds on an@INCsearch.$@- set bydo EXPRon compile failure; cleared on success.$!- set bydo EXPRon I/O failure (file could not be read).$0,__FILE__,__LINE__- the currently compiling filename is set to the file being loaded whiledo EXPRparses it, so warnings anddiemessages point at the right file.
do BLOCK touches no globals; it is a pure syntactic construct.
Edge cases#
do BLOCKis not a loop.next,last, andredoinside ado … whiledo not apply to the block. Use a bare block or a realwhileloop.returnindo BLOCKreturns from the enclosing sub. Not from the block. There is no way to return a value from ado BLOCKother than making it the last expression evaluated.Statement modifiers are pre-test everywhere else.
STATEMENT while CONDtests first;do BLOCK while CONDtests after the first run. This is a deliberate language exception.Relative paths without
./search@INC. Since 5.26,.is not in@INC, sodo 'stat.pl'does not mean “current directory file” any more; pass./stat.plif that was the intent.do EXPRcannot see enclosing lexicals. The file is parsed as if at the top level. If you need access to lexicals, useeval STRING- with the usual taint and injection caveats.The file is re-parsed every call.
do EXPRis not cached via%INCthe wayrequireis. Calling it in a loop re-reads and re-compiles the file each iteration.Check
$@before$!. A compilation failure can also set$!as a side effect; the compile error in$@is the one you actually want to report.A file that compiles but returns a false value is ambiguous.
unless ($ret = do $file) { … }fires for both “file failed” and “file ran and returned0”. If your config file is allowed to end in a false value, usedefinedand$@explicitly instead of truth-testing the return.dowith no argument is a syntax error. Both forms require a term: a block or an expression.
Differences from upstream#
Fully compatible with upstream Perl 5.44.
See also#
eval-eval BLOCKtraps exceptions without reading a file;eval STRINGparses arbitrary code and can see enclosing lexicals, unlikedo EXPRrequire- load a library file with%INCcaching and automatic exception on failure; the right tool for modulesreturn- note thatreturninsidedo BLOCKreturns from the enclosing subroutine, not from the block@INC- module search path consulted bydo EXPRon relative filenames%INC- records the resolved path after a successful@INC-searcheddo EXPR$@- compile-time error fromdo EXPR$!- I/O error fromdo EXPRwhen the file cannot be read