为什么在使用`do`函数时无法加载Perl库?

Nic*_*ton 4 perl subroutine

我是Perl的新手,我正在更新一个旧的Perl网站.每个.pl文件似乎都在顶部有这一行:

do "func.inc";
Run Code Online (Sandbox Code Playgroud)

所以我想我可以使用这个文件来标记子程序以供全局使用.

func.inc

#!/usr/bin/perl
sub foobar
{
    return "Hello world";
}
Run Code Online (Sandbox Code Playgroud)

index.pl

#!/usr/bin/perl
do "func.inc";
print "Content-type: text/html\n\n";
print foobar();
Run Code Online (Sandbox Code Playgroud)

但是,我收到此错误:

Undefined subroutine &main::foobar called at /path/to/index.pl line 4.
Run Code Online (Sandbox Code Playgroud)

这两个文件都在同一个目录中,并且func.inc已经有整个网站使用的sub的音调.但是,该脚本适用于Linux生产环境,但不适用于我的Windows 7开发环境(我正在使用ActivePerl).

更新:

看起来文件没有被包含在内; 如果使用绝对路径包含文件,则子工作正常...

do "C:/path/to/func.inc";
Run Code Online (Sandbox Code Playgroud)

...所以看起来相对路径不适用于我的本地开发环境,但它们可以在生产环境中工作.但这对我没有好处,因为我的开发机器上的绝对路径不适用于实时服务器.

如何do在Windows 7开发机器上使用相对路径开始工作?

更新2:

我正在使用Perl -T开关.不幸的是,这删除了"." 来自@INC,因此阻止我们使用相对路径do.我删除了此开关,旧代码现在正在运行.我知道这不是好习惯,但不幸的是我正在处理旧代码,所以我似乎别无选择.

Gre*_*con 6

读取的perlfunc文档do

所以看看这一切在行动中,说C:\Cygwin\tmp\mylib\func.inc看起来像

sub hello {
  print "Hello, world!\n";
}

1;
Run Code Online (Sandbox Code Playgroud)

我们在以下程序中使用它:

#!/usr/bin/perl

use warnings;
use strict;

# your code may have unshift @INC, ...
use lib "C:/Cygwin/tmp/mylib";

my $func = "func.inc";

do $func;

# Now we can just call it. Note that with strict subs enabled,
# we have to use parentheses. We could also predeclare with
# use subs qw/ hello /; 
hello();

# do places func.inc's location in %INC
if ($INC{$func}) {
  print "$0: $func found at $INC{$func}\n";
}
else {
  die "$0: $func missing from %INC!";
}
Run Code Online (Sandbox Code Playgroud)

它的输出是

Hello, world!
./prog: func.inc found at C:/Cygwin/tmp/mylib/func.inc

如您所见,do并非总是没有水晶楼梯,do文档解释如下:

如果do无法读取文件,则返回undef并设置$!为错误.如果可以读取文件但无法编译它,则返回undef并设置错误消息$@.如果文件成功编译,则do返回最后计算的表达式的值.

要检查所有这些情况下,我们就可以不再使用简单do "func.inc",但

unless (defined do $func) {
  my $error = $! || $@;
  die "$0: do $func: $error";
}
Run Code Online (Sandbox Code Playgroud)

每种情况的解释如下.

do 无法读取文件

如果我们重命名func.incnope.inc并重新运行程序,我们得到

./prog: do func.inc: No such file or directory at ./prog line 12.

do 可以读取文件但无法编译

重命名nope.incfunc.inc并删除右大括号hello,使其看起来像

sub hello {
  print "Hello, world!\n";

1;
Run Code Online (Sandbox Code Playgroud)

现在运行程序,我们得到

./prog: do func.inc: Missing right curly or square bracket at C:/Cygwin/tmp/mylib/func.inc line 4, at end of line
syntax error at C:/Cygwin/tmp/mylib/func.inc line 4, at EOF

do 可以读取文件并编译它,但它不会返回真值.

删除1;最后一个func.inc来制作它

sub hello {
  print "Hello, world!\n";
}
Run Code Online (Sandbox Code Playgroud)

现在输出是

./prog: do func.inc:  at ./prog line 13.

因此,如果没有返回值,成功就像失败一样.我们可以使检查结果的代码复杂化do,但更好的选择是始终在Perl库和模块的末尾返回一个真值.

请注意,即使-T启用了污点检查(),程序也能正确运行.试试看吧!一定要阅读污点模式和@INCperlsec.