只是无法使perl按预期工作(条件和变量声明)

时间:2010-07-14 06:48:33

标签: perl cgi

修改

这次我会尝试更好的解释,这是我的脚本中的确切代码(对不起他们所有的内容,他们是你的sugestions的结果,以及下面视频中的apear)。

#use warnings;
#use Data::Dumper;
open(my $tmp_file, ">>", "/tmp/some_bad.log") or die "Can not open log file: $!\n";
#if( $id_client != "")
@allowed_locations = ();
#print $tmp_file "Before the if: ". Data::Dumper->Dump([\@allowed_locations, $id_client]) . "";
if( $id_client )
{
#    print $tmp_file "Start the if: ". Data::Dumper->Dump([\@allowed_locations, $id_client]) . "";
#    my $q = "select distinct id_location from locations inner join address using (id_db5_address) inner join zona_rural_detaliat using (id_city) where id_client=$id_client";
#    my $st =  &sql_special_transaction($sql_local_host, $sql_local_database, $sql_local_root, $sql_local_root_password, $q);
#    print $tmp_file "Before the while loop: ref(st)='". ref($st) . "\n";
#    while((my $id)=$st->fetchrow())
#    {
#       print $tmp_file "Row the while loop: ". Data::Dumper->Dump([$id])  . "";
#       my $id = 12121212;
#       push(@allowed_locations, $id);
#    }
#    print $tmp_file "After the while loop: ref(st)='". ref($st) . "\n";
#    my($a) = 1;
#} else {
#    my($a) = 0;    
}
#print $tmp_file "After the if: ". Data::Dumper->Dump([\@allowed_locations, $id_client]) . "";
close($tmp_file) or die "Can not close file: $!\n";
#&html_error(@allowed_locations);

首先,有人说我应该尝试在命令行中运行它,脚本在命令行中运行正常(没有警告,它当时没有注释),但是当triyng要在浏览器中通过apache加载它失败,请参阅this video我捕获脚本行为的位置,我试图在视频中显示的内容:

我打开了2个标签,第一个没有定义变量$ id_client,第二个定义了从GET读取的变量$ id_client:?id_client = 36124 => $ id_client = 36124; ,两者都包含视频“ locallib.pl ”中的库

  1. 用所有的脚本运行脚本时 新代码评论页面加载
  2. 解开定义的行时 @allowed_locations =(); 脚本失败
  3. 留下这个定义和解开 if块,以及。的定义 if块中的 my $ a; ;现在,当$ id_client为时,脚本工作正常 已定义,但在$ id_client时失败 未定义
  4. 解开else块和 在else中定义 my $ a; 块。现在脚本运行正常 有或没有$ id_client
  5. 现在评论所有 my $ a; 定义和评论其他 阻止,脚本失败
  6. 但如果我使用 open()打开 IF之前的文件,和 关闭()关闭它,如果它没有失败,即使IF块 是空的,如果没有,则为事件 否则阻止
  7. 我在命令行中运行脚本时复制了所有步骤,并且每个步骤后脚本都有效 我知道这听起来不像剧本的行为,但请观看视频(2分钟),也许你会注意到我在那里做错了。

    使用perl版本:

    [root@db]# perl -v
    This is perl, v5.8.6 built for i386-linux-thread-mult
    

    有人问我是否没有测试服务器,回答:不,我的公司有一个具有多种用途的生产服务器,不仅仅是Web界面,而且我无法冒险更新内核或perl版本,以及不能冒险安装任何debuger,因为公司老板说:“如果它有效,请不要管它”,对于他们来说我($ a); 的解决方案是完美的,因为它有效,我是在这里问我,了解更多有关perl的信息,了解出了什么问题以及下次我能做些什么。

    谢谢。

    P.S。希望这种新方法能够恢复我的一些-1:)

    修改 我成功启动了错误日志记录,并在每个导致失败的步骤后在错误日志中找到了这个消息我得到了这个消息:
    [2010年7月15日星期四14:29:19] [错误] locallib.pl未在/var/www/html/rdsdb4/cgi-bin/clients/quicksearch.cgi第2行返回真值。
    [2010年7月15日星期四14:29:19] [错误]脚本标题过早结束:quicksearch.cgi

    我发现这个代码位于locallib.pl主代码的末尾,之后有子定义,而locallib.pl是一个库而不是程序文件,所以它的最后一个语句必须返回true。,库末尾的一个简单的 1; 语句确保(我把它放在子定义之后,以确保没有人在1;之后在main中写代码)和问题得到解决 不知道为什么在CLI中没有问题...

    也许我现在会得到很多票数(温柔:)),但我能做些什么......我希望有些新手会读到这些并从我的错误中学到一些东西。

    谢谢大家的帮助。

6 个答案:

答案 0 :(得分:4)

  1. 您需要明确检查定义。

    如果要在定义$ client时进入循环, 使用if ( defined $client )

    如果要在定义$ client和有效整数时进入循环, 使用if ( defined $client && $client =~ /^-?\d+$/ )。 我假设它是来自上下文的整数,如果它可以是一个浮点数,则需要增强正则表达式 - 有一个标准的Perl库包含预先制作的正则表达式,包括匹配浮点数的正则表达式。如果您需要非负的int,请从正则表达式的开头删除-?

    如果你想在定义$ client时输入循环并且非零(并假设它不应该是空字符串), 使用if ( $client )

    如果要在定义$ client和有效的非零int时进入循环, 使用if ( $client && $client =~ /^-?\d+$/ )

  2. if条件为false时,您的@ids为“undef”,如果它依赖于@ids为数组,则可能会在以后破坏代码。由于您没有实际指定如何脚本在没有else的情况下中断,因此这是最可能的原因。

  3. 请查看这个版本是否有效(使用上面你需要的“if”条件,我选择了最后一个,因为它看起来与最接近的原始代码的意图匹配 - 只输入非零整数):

    调试更新后的代码

    use Data::Dumper;
    open(my $tmp_file, ">", "/tmp/some_bad.log") or die "Can not open log file: $!\n";
    @ids = (); # Do this first so @ids is always an array, even for non-client!
    print $tmp_file "Before the if: ". Data::Dumper->Dump([\@ids, $client]) . "\n";
    if ( $client && $client =~ /^-?\d+$/ ) # First expression catches undef and zero
    {
        print $tmp_file "Start the if: ". Data::Dumper->Dump([\@ids, $client]) . "\n";
        my $st = &sql_query("select id from table where client=$client");
        print $tmp_file "Before the while loop: ref(st)='". ref($st) . "'\n";
        while(my $row = $st->fetchrow())
        {
           print $tmp_file "Row the while loop: ". Data::Dumper->Dump([row])  . "'\n";
           push(@ids, $row->[0]);
        }
        print $tmp_file "After the while loop: ref(st)='". ref($st) . "'\n";
        # No need to undef since both variables are lexically in this block only
    }
    print $tmp_file "After the if\n";
    close($tmp_file) or die "Can not close file: $!\n";
    

答案 1 :(得分:3)

检查字符串时,==和!=应分别为'eq'或'ne'

if( $client != "" )

应该是

if( $client ne "" )

否则你没有得到你期望得到的东西。

答案 2 :(得分:2)

注意:此答案已删除,因为我认为这不是一个真正的问题。为了拯救其他人重复此事,我取消删除它。

而不是

if( $client != "" )

if ($client)

此外,如果您

,Perl调试会更容易
 use warnings;
 use strict;

答案 3 :(得分:2)

始终以:

开始您的脚本
use warnings;
use strict;

这些将为您提供有用的信息。

然后你可以写:

my @ids;

if (defined $client) {
    @ids = (); # not necessary if you run this part only once
    my $st = sql_query("select id from table where client=$client");
    while( my ($id) = $st->fetchrow ) {
       push @ids, $id;
    }
} else {
    warn '$client not defined';
}

if (@ids) {  # Your query returned something
    # do stuff with @ids
} else {
    warn "client '$client' does not exist in database";
}

答案 4 :(得分:0)

我发现这个代码位于locallib.pl主代码的末尾,之后有子定义,而locallib.pl是一个库而不是程序文件,所以它的最后一个语句必须返回true ,简单1;库末尾的语句确保(在子定义之后放置它以确保没有人在1之后在main中写代码)并且问题得到修复。

结论:
我了解到每次编写库或修改库时,请确保它的最后一个参数返回true;

答案 5 :(得分:-4)

哦,我的......试试这个例子......

# Move the logic into a subroutine
# Forward definition so perl knows func exists
sub getClientIds($);       

# Call subroutine to find id's - defined later.
my @ids_from_database = &getClientIds("Joe Smith");

# If sub returned an empty list () then variable will be false.
# Otherwise, print each ID we found.

if (@ids_from_database) {
    foreach my $i (@ids_from_database) {
        print "Found ID $i \n";
    }
} else {
    print "Found nothing! \n";
}

# This is the end of the "main" code - now we define the logic.

# Here's the real work    
sub getClientIds($) {
    my $client = shift @_;       # assign first parameter to var $client
    my @ids    = ();             # what we will return

    # ensure we weren't called with &getClientIds("") or something...
    if (not $client) {
        print "I really need you to give me a parameter...\n";
        return @ids;
    }

    # I'm assuming the query is string based, so probably need to put it 
    # inside \"quotes\"
    my $st = &sql_query("select id from table where client=\"$client\"");

    # Did sql_query() fail?
    if (not $st) {
        print "Oops someone made a problem in the SQL...\n";
        return @ids;
    }

    my @result;

    # Returns a list, so putting it in a list and then pulling the first element
    # in two steps instead of one.
    while (@result = $st->fetchrow()) {
        push @ids, $result[0];
    }

    # Always a good idea to clean up once you're done.
    $st->finish();

    return @ids;
}

针对您的具体问题:

  1. 如果你想测试是否定义了$ client,你需要“if(eval {defined $ client;})”,但这几乎肯定是你是什么正在寻找!确保$ client在程序的早期有一些定义(例如 $ client =“”; )要容易得多。另请注意Kaklon关于 ne 之间差异的答案!
  2. if(X){stuff} else {} 无效perl。你可以这样做: if(X){stuff} else {1; } 但这有点乞求这个问题,因为真正的问题是对变量的测试,而不是else子句。
  3. 对不起,没有任何线索 - 我认为问题出在其他地方。
  4. 我也回应Kinopiko建议你在程序开始时添加“use strict;”。这意味着你使用的任何$变量@that%必须预先定义为“我的$ varable;我的@that;我的%你;”这似乎更多的工作,但它的工作更少而不是尝试在代码中处理未定义的变量和定义的变量。这是一个很好的习惯。

    请注意,我的变量只存在于定义它们的squiggliez中(整个文件周围存在隐含的squiggliez:

    my $x = 1;
    if ($x == 1) 
    {
        my $x = 2;
        print "$x \n";    # prints 2. This is NOT the same $x as was set to 1 above.
    }
    print "$x \n";        # prints 1, because the $x in the squiggliez is gone.