4

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

do "func.inc";

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

函数公司

#!/usr/bin/perl
sub foobar
{
    return "Hello world";
}

索引.pl

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

但是,我收到此错误:

Undefined subroutine &main::foobar called at /path/to/index.pl line 4.

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

更新:

看起来该文件未包含在内;如果使用绝对路径包含文件,则 sub 工作...

do "C:/path/to/func.inc";

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

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

更新 2:

我正在使用 Perl-T开关。不幸的是,这删除了“。” 来自@INC,因此阻止我们使用相对路径do。我删除了这个开关,旧代码现在可以工作了。我知道这不是一个好习惯,但不幸的是我正在使用旧代码,所以我似乎别无选择。

4

5 回答 5

6

用于读取的perlfunc 文档do

  • do EXPR
    使用 的值EXPR作为文件名,并将文件的内容作为 Perl 脚本执行。

    do 'stat.pl';
    

    就像

    eval `cat stat.pl`;
    

    除了它更高效、更简洁、跟踪当前文件名以查找错误消息、搜索@INC目录并%INC在找到文件时进行更新。

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

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

1;

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

#!/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!";
}

它的输出是

你好世界!
./prog: func.inc 位于 C:/Cygwin/tmp/mylib/func.inc

正如您所观察到的,do并不总是没有水晶楼梯,do文档解释说:

如果do无法读取文件,则返回undef并设置$!为错误。如果 do 可以读取文件但不能编译它,它会返回undef并在$@. 如果文件编译成功,do返回最后一个表达式的值。

要检查所有这些情况,我们不能再简单地do "func.inc"使用

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

每种情况的解释如下。

do无法读取文件

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

./prog: do func.inc: ./prog 第 12 行没有这样的文件或目录。

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

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

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

1;

现在运行程序,我们得到

./prog: do func.inc: 在 C:/Cygwin/tmp/mylib/func.inc 第 4 行,行尾缺少右花括号或方括号
C:/Cygwin/tmp/mylib/func.inc 第 4 行 EOF 处的语法错误

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

删除1;末尾func.inc

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

现在输出是

./prog:执行 func.inc:在 ./prog 第 13 行。

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

请注意,即使-T启用了污点检查 ( ),程序也可以正常运行。试试看!请务必阅读Taint mode 和@INCperlsec

于 2010-01-10T12:54:53.180 回答
3

您使用子程序的方式与使用任何其他子程序的方式相同。加载它并不重要do。但是,您不应该使用do它。查看Intermediate Perl中的“包”一章,了解从其他文件加载子例程的详细说明。简而言之,请改用require

请参阅do的文档。您需要在 Perl 将查找库的目录之一中有func.inc(您也可以只调用func.pl,因为pl是“perl 库”)。这可能与具有index.pl的目录不同。将func.inc放在@INC某处,或将其目录添加到@INC. do如果它无法加载文件也不会死,所以它不会告诉你它失败了。这就是为什么你不应该使用do来加载库。:)

于 2010-01-10T11:34:29.237 回答
2

确保路径正确,使用:


#!/usr/bin/perl 
require("func.inc");
print "Content-type: text/html\n\n"; 
print foobar(); 
于 2010-01-10T11:56:25.783 回答
1

我会首先检查文件是否实际加载,文档中do提到%INC如果找到文件就会更新。文档中还有更多信息。

于 2010-01-10T11:34:06.477 回答
0

确保 func.inc 在正确的路径中。

do "func.inc" 

意味着您说 func.inc 与您的 perl 脚本在同一路径中。检查正确的路径,然后执行此操作

do "/path/func.inc"
于 2010-01-10T11:37:20.050 回答