我有一个无效的Perl脚本,我不知道如何开始缩小问题范围。我该怎么办?
注意:我正在添加问题,因为我真的想在Stackoverflow中添加我非常冗长的答案。我在其他答案中保持外部链接,它值得在这里。如果你有什么要补充的话,不要羞于编辑我的答案。
答案 0 :(得分:125)
答案 1 :(得分:10)
我认为CGI::Debug也值得一提。
答案 2 :(得分:8)
我想知道为什么没有人提到名为PERLDB_OPTS
的{{1}}选项;虽然可以肯定的是,网络上的工作示例并不多(RemotePort
中甚至没有提到RemotePort
) - 而且我提出这个问题有点问题,但是这里有一个问题。 (这是一个Linux示例)。
为了做一个正确的例子,首先我需要一些可以对CGI Web服务器进行非常简单的模拟的东西,最好是通过一个命令行。找到perldebug后,我发现Simple command line web server for running cgis. (perlmonks.org)适用于此测试。
在这里,我将在/tmp
目录中工作; CGI脚本将为/tmp/test.pl
(包括在下面)。请注意,IO::All
服务器仅提供与CGI位于同一目录中的可执行文件,因此此处需要chmod +x test.pl
。因此,要进行通常的CGI测试运行,我将目录更改为终端中的/tmp
,并在那里运行单行Web服务器:
$ cd /tmp
$ perl -MIO::All -e 'io(":8080")->fork->accept->(sub { $_[0] < io(-x $1 ? "./$1 |" : $1) if /^GET \/(.*) / })'
webserver命令将在终端中阻塞,否则将在本地启动Web服务器(在127.0.0.1或localhost
) - 之后,我可以转到Web浏览器,并请求此地址:
http://127.0.0.1:8080/test.pl
...我应该在网络浏览器中观察由print
加载并显示的test.pl
。
现在,要使用RemotePort
调试此脚本,首先我们需要网络上的侦听器,我们将通过它与Perl调试器进行交互;我们可以使用命令行工具netcat
(nc
,在此处查看:IO::All - A Tiny Web Server)。因此,首先在一个终端中运行netcat
侦听器 - 它将阻塞并等待端口7234上的连接(这将是我们的调试端口):
$ nc -l 7234
然后,当perl
被调用时(即使在CGI模式下,通过服务器),我们希望RemotePort
以test.pl
启动调试模式。在Linux中,这可以使用以下“shebang wrapper”脚本完成 - 这里也需要在/tmp
中,必须可执行:
cd /tmp
cat > perldbgcall.sh <<'EOF'
#!/bin/bash
PERLDB_OPTS="RemotePort=localhost:7234" perl -d -e "do '$@'"
EOF
chmod +x perldbgcall.sh
这有点棘手 - 请参阅Perl如何remote debug?。但是,这里的诀窍似乎是 not 来分叉处理perl
的{{1}}解释器 - 所以一旦我们点击它,我们就不会test.pl
,但是相反,我们使用exec
“明白地”调用perl
,并基本上“来源”我们的test.pl
脚本。(请参阅shell script - How can I use environment variables in my shebang? - Unix & Linux Stack Exchange)。
现在我们在do
中有perldbgcall.sh
- 我们可以更改/tmp
文件,以便它在其shebang行(而不是通常的Perl解释器)上引用此可执行文件 - 这里修改test.pl
:
/tmp/test.pl
现在,#!./perldbgcall.sh
# this is test.pl
use 5.10.1;
use warnings;
use strict;
my $b = '1';
my $a = sub { "hello $b there" };
$b = '2';
print "YEAH " . $a->() . " CMON\n";
$b = '3';
print "CMON " . &$a . " YEAH\n";
$DB::single=1; # BREAKPOINT
$b = '4';
print "STEP " . &$a . " NOW\n";
$b = '5';
print "STEP " . &$a . " AGAIN\n";
及其新的shebang处理程序test.pl
都位于perldbgcall.sh
;我们/tmp
监听端口7234上的调试连接 - 所以我们最终可以打开另一个终端窗口,将目录更改为nc
,然后运行一线网络服务器(将侦听端口上的Web连接) 8080)那里:
/tmp
完成此操作后,我们可以转到我们的网络浏览器,并请求相同的地址cd /tmp
perl -MIO::All -e 'io(":8080")->fork->accept->(sub { $_[0] < io(-x $1 ? "./$1 |" : $1) if /^GET \/(.*) / })'
。但是,现在当Web服务器尝试执行脚本时,它将通过http://127.0.0.1:8080/test.pl
shebang执行此操作 - 这将在远程调试器模式下启动perldbgcall.sh
。因此,脚本执行将暂停 - 因此Web浏览器将锁定,等待数据。我们现在可以切换到perl
终端,我们应该看到熟悉的Perl调试器文本 - 但是,通过netcat
输出:
nc
正如代码段所示,我们现在基本上使用$ nc -l 7234
Loading DB routines from perl5db.pl version 1.32
Editor support available.
Enter h or `h h' for help, or `man perldebug' for more help.
main::(-e:1): do './test.pl'
DB<1> r
main::(./test.pl:29): $b = '4';
DB<1>
作为“终端” - 因此我们可以为“运行”键入nc
(和Enter) - 脚本将运行断点声明(另请参阅How do I run a Perl script from within a Perl script?),再次停止之前(请注意,此时浏览器仍会锁定)。
所以,现在我们可以通过r
终端逐步完成test.pl
的其余部分:
nc
...但是,此时,浏览器还会锁定并等待数据。只有在我们使用....
main::(./test.pl:29): $b = '4';
DB<1> n
main::(./test.pl:30): print "STEP " . &$a . " NOW\n";
DB<1> n
main::(./test.pl:31): $b = '5';
DB<1> n
main::(./test.pl:32): print "STEP " . &$a . " AGAIN\n";
DB<1> n
Debugged program terminated. Use q to quit or R to restart,
use o inhibit_exit to avoid stopping after program termination,
h q, h R or h o to get additional info.
DB<1>
退出调试器后:
q
...浏览器是否会停止锁定 - 最后显示 DB<1> q
$
的
test.pl
当然,即使不运行Web服务器也可以进行这种调试 - 但是,这里的巧妙之处在于我们根本不接触Web服务器;我们从Web浏览器“本机地”(对于CGI)触发执行 - 并且CGI脚本本身所需的唯一更改是shebang的更改(当然,shebang包装脚本的存在,作为可执行文件在同一个中)目录)。
嗯,希望这有助于某人 - 我肯定会喜欢偶然发现这一点,而不是自己写YEAH hello 2 there CMON
CMON hello 3 there YEAH
STEP hello 4 there NOW
STEP hello 5 there AGAIN
干杯!
答案 3 :(得分:7)
die
语句和其他致命的运行时和编译时错误
打印到STDERR
,这很难找到,可能会被混淆
来自您网站的其他网页的消息。当你正在调试你的
脚本,这是一个好主意,让你的致命错误信息显示在你的
浏览器莫名其妙。
执行此操作的一种方法是致电
use CGI::Carp qw(fatalsToBrowser);
位于脚本的顶部。 That call将在浏览器中安装$SIG{__DIE__}
处理程序(请参阅perlvar)显示致命错误,必要时在前面添加有效标头。在我听说CGI::Carp
之前我使用的另一个CGI调试技巧是
使用eval
与脚本上的DATA
和__END__
工具来捕获编译时错误:
#!/usr/bin/perl
eval join'', <DATA>;
if ($@) { print "Content-type: text/plain:\n\nError in the script:\n$@\n; }
__DATA__
# ... actual CGI script starts here
这种更详细的技术比CGI::Carp
略有优势,因为它会捕获更多的编译时错误。
更新:我从未使用它,但看起来像CGI::Debug
,就像Mikael S
建议,也是一个非常有用和可配置的工具。
答案 4 :(得分:5)
对我来说,我使用log4perl。它非常实用且简单。
use Log::Log4perl qw(:easy);
Log::Log4perl->easy_init( { level => $DEBUG, file => ">>d:\\tokyo.log" } );
my $logger = Log::Log4perl::get_logger();
$logger->debug("your log message");
答案 5 :(得分:1)
可能还值得一提的是,Perl将始终告诉您从命令行执行Perl脚本时出现错误的行。 (例如,SSH会话)
如果一切都失败了,我通常会这样做。我将SSH到服务器并手动执行Perl脚本。例如:
% perl myscript.cgi
如果出现问题,Perl会告诉您相关信息。此调试方法可以消除任何与文件权限相关的问题或Web浏览器或Web服务器问题。
答案 6 :(得分:1)
老实说,你可以在这篇文章上面做所有有趣的事情。 尽管如此,我发现最简单,最主动的解决方案就是“打印”。
在示例中: (普通代码)
`$somecommand`;
看看它是否正在做我真正想做的事情: (故障排除)
print "$somecommand";
答案 7 :(得分:0)
您可以使用以下命令
在终端中运行perl cgi-script $ perl filename.cgi
它解释代码并使用HTML代码提供结果。如果有的话,它将报告错误。