我是Perl的新手,我正在更新一个旧的Perl网站。每个.pl
文件似乎都在顶部有这一行:
do "func.inc";
所以我想我可以使用这个文件来标记子程序以供全局使用。
#!/usr/bin/perl
sub foobar
{
return "Hello world";
}
#!/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
中已经有了整个网站使用的潜在音调。但是,该脚本适用于Linux生产环境,但不适用于我的Windows 7开发环境(我正在使用ActivePerl)。
看起来文件没有被包含在内;如果使用绝对路径包含文件,则子工作...
do "C:/path/to/func.inc";
...所以看起来相对路径不适用于我的本地开发环境,但它们可以在生产环境中工作。但这对我没有好处,因为我的开发机器上的绝对路径不适用于实时服务器。
如何在Windows 7开发计算机上使用相对路径让do
工作?
我使用的是Perl -T
开关。不幸的是,这删除了“。”来自@INC,因此阻止我们使用do
的相对路径。我删除了此开关,旧代码现在正在运行。我知道这不是一个好习惯,但不幸的是我正在处理旧代码,所以我似乎别无选择。
答案 0 :(得分:6)
perlfunc documentation for 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!";
}
它的输出是
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";
}
每个案例的解释如下。
do
无法读取文件如果我们将func.inc
重命名为nope.inc
并重新运行该计划,我们就会
./prog: do func.inc: No such file or directory at ./prog line 12.
do
可以读取文件但无法编译将nope.inc
重命名为func.inc
并删除hello
中的结束大括号,使其看起来像
sub hello {
print "Hello, world!\n";
1;
现在运行程序,我们得到
./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";
}
现在输出
./prog: do func.inc: at ./prog line 13.
因此,如果没有返回值,成功就像失败一样。我们可能会复杂检查do
结果的代码,但更好的选择是始终在Perl库和模块的末尾返回一个真值。
请注意,即使启用了污点检查(-T
),程序也能正常运行。试试看吧!请务必阅读Taint mode and @INC
in perlsec。
答案 1 :(得分:3)
您使用子程序的方式与使用任何其他子程序的方式相同。用do
加载它并不重要。但是,您不应该使用do
。查看Intermediate Perl中的“软件包”一章,了解从其他文件加载子程序的详细说明。简而言之,请改用require。
请参阅do的文档。您需要 func.inc (您也可以在 func.pl 中调用 func.pl ,因为 pl 是“perl库”) Perl将查找库的目录。这可能与 index.pl 的目录不同。将 func.inc 放在@INC
的某处,或将其目录添加到@INC
。 do
如果无法加载文件也不会死亡,因此它不会告诉您它失败了。这就是为什么你不应该使用do
来加载库。 :)
答案 2 :(得分:2)
确保路径正确,请使用:
#!/usr/bin/perl
require("func.inc");
print "Content-type: text/html\n\n";
print foobar();
答案 3 :(得分:1)
我首先检查文件是否实际加载,documentation for do
提及如果找到文件,它会更新%INC
。文档中还有更多信息。
答案 4 :(得分:0)
确保您在正确的路径中有func.inc。
do "func.inc"
表示您说func.inc与perl脚本位于同一路径中。检查正确的路径,然后执行此操作
do "/path/func.inc"