I’m writing a script that will take input from user in order to load a configuration/data file.
My first though was (assume the file name is in $file
):
if (-e $file) {
my $data = do $file;
die "Failed to parse datan" if $@;
} else {
die "File does not existn";
}
This works to a certain extent — if the file does not exist it dies accordingly. However, if it does, and is not a full path (beginning with /
) and instead is relative to current directory, it dies with a message coming from Perl:
[…] ‘.’ is no longer in @INC; did you mean do […]
Why is that? I don’t want to add .
to @INC
, but I’m surprised that this didn’t die with my message instead. Shouldn’t it just fail the do and set $@
?
How can I test that a file exists and is in reach of @INC
? Or, maybe another solution, like reliably testing for the path in the current directory and making it a full path before passing to do
.
6
Your code does not produce the message you say it does, but do EXPR
can produce that warning.
$ touch foo # The file must exist for the warning to be produced.
$ perl -e'do "foo"'
do "foo" failed, '.' is no longer in @INC; did you mean do "./foo"? at -e line 1.
You can silence the warning using
no warnings qw( deprecated );
The reason it warns is because it used to “work” (as long as the current work directory happened to be the script’s directory), but a change to Perl caused it to stop working.
do
only sets $@
if there’s an exceptions from the compilation/execution of the file. Inability to access the file only sets $!
.
Don’t use code as configuration. Use a common format like JSON, YAML, TOML, INI, or whatever. There are plenty of modules that can handle any of those. I have an entire chapter on this in Mastering Perl.
As for your question, Perl removed the current working directory from the default module search path in v5.26 so people can’t drop their own module in the current directory and trick your program into executing unexpected and possibly malicious code. That’s what you’re trying to re-allow.
3