我是Perl的新手,我正在更新一个旧的Perl网站.每个.pl
文件似乎都在顶部有这一行:
do "func.inc";
Run Code Online (Sandbox Code Playgroud)
所以我想我可以使用这个文件来标记子程序以供全局使用.
#!/usr/bin/perl
sub foobar
{
return "Hello world";
}
Run Code Online (Sandbox Code Playgroud)
#!/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开发机器上使用相对路径开始工作?
我正在使用Perl -T
开关.不幸的是,这删除了"." 来自@INC,因此阻止我们使用相对路径do
.我删除了此开关,旧代码现在正在运行.我知道这不是好习惯,但不幸的是我正在处理旧代码,所以我似乎别无选择.
读取的perlfunc文档do
do EXPR
使用EXPR
作为文件名的值并以Perl脚本的形式执行文件的内容.Run Code Online (Sandbox Code Playgroud)do 'stat.pl';
就像
Run Code Online (Sandbox Code Playgroud)eval `cat stat.pl`;
除了它更有效和简洁,跟踪错误消息的当前文件名,搜索
@INC
目录,并更新%INC
文件是否找到.
所以看看这一切在行动中,说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.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;
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
启用了污点检查(),程序也能正确运行.试试看吧!一定要阅读污点模式和@INC
perlsec.