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.42.
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