代码之家  ›  专栏  ›  技术社区  ›  Radu Maris

只是不能让Perl按预期工作(条件和变量声明)

  •  -2
  • Radu Maris  · 技术社区  · 14 年前

    编辑:

    这次我将尝试更好的解释,这是我的脚本中的确切代码(对所有这些内容表示抱歉,它们是您的建议和下面视频中的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 在这里,我捕获了脚本行为,我试图在视频中显示的内容:

    我打开了两个选项卡,第一个选项卡没有定义变量$id_client,第二个选项卡定义从get:读取的变量$id_client。id_client=36124=> $id_客户端=36124; ,两者都包括视频中的库“ 局部钙

    1. 当运行脚本时, 新代码注释了页面加载
    2. 取消对定义的行的注释时 这个 @允许的位置=); 这个 脚本失败
    3. 保留此定义并取消注释 if块,以及 我的美元; 在if块中;当$id_客户机 已定义,但在$id_客户端时失败 未定义
    4. 取消对else块和 定义 我的美元; 在其他 块。现在脚本可以正常工作了 有或没有$id_客户
    5. 现在评论所有 我的美元; 定义和评论其他 阻止,脚本失败
    6. 但如果我用 打开() 打开 提交给国际单项体育联合会的文件,以及 关闭() 在if之后关闭它,即使if块 为空,如果没有 其他块

    在命令行中运行脚本时,我已经复制了所有步骤,并且脚本在每个步骤之后都工作。
    我知道这听起来不像是脚本的行为,但是请看视频(2分钟),也许你会注意到我在那里做错了什么。

    使用Perl版本:

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

    有人问我是否没有测试服务器,回答:不,我的公司有一个多用途的生产服务器,不仅仅是Web界面,我不能冒险更新内核或Perl版本,也不能冒险安装任何调试程序,正如公司所有者所说:“如果它能用,就让它单独运行”,对于他们来说,解决方案是 我的(一美元); 是完美的,因为它是有效的,我在这里只是为了我,了解更多关于Perl的知识,了解出了什么问题,下一次我能做得更好。

    谢谢您。

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

    编辑: 我成功地启动了错误日志记录,并在导致失败的每个步骤之后在错误日志中找到了此错误。我收到了以下消息:
    [星期四2010年7月15日14:29:19][error]locallib.pl在/var/www/html/rdsdb4/cgi-bin/clients/quicksearch.cgi行2没有返回真值。
    [星期四7月15日14:29:19 2010][error]脚本头过早结束:quicksearch.cgi

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

    也许我现在会得到很多低票(温柔地说:),但是我能做些什么……我希望一些新手能读到这篇文章,从我的错误中吸取教训。

    谢谢大家的帮助。

    6 回复  |  直到 14 年前
        1
  •  4
  •   DVK    14 年前
    1. 您需要明确检查定义。

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

      如果要在定义$client和有效整数时输入循环, 使用 if ( defined $client && $client =~ /^-?\d+$/ ) . 我假设它是上下文中的一个整数,如果它可以是一个浮点型,则需要增强regex——有一个标准的perl库,其中包含预封装的regex,包括与float匹配的regex。如果需要非负整数,请删除 -? 从Regex开始。

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

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

    2. 您的@id是“undef”,当 if 条件为false,如果依赖@ids作为数组,则稍后可能会破坏代码。因为你没有具体说明 怎样 脚本在没有 else ,这是最可能的原因。

    请查看此版本是否有效(使用上面您需要的“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";
    
        2
  •  3
  •   kaklon    14 年前

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

    if( $client != "" )
    

    应该是

    if( $client ne "" )
    

    否则你就得不到你期望得到的。

        3
  •  2
  •   Toto    14 年前

    总是 脚本开头:

    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
  •  2
  •   4 revs<br/>user181548&#13;    14 年前

    注意:这个答案被删除了,因为我认为这不是一个真正的问题。我不想为了拯救别人重复这个。

    而不是

    if( $client != "" )
    

    尝试

    if ($client)
    

    此外,如果您

     use warnings;
     use strict;
    
        5
  •  0
  •   Radu Maris    14 年前

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

    结论:
    我知道,每次你写一个库或者修改一个库,确保它的最后一个语句返回真的;

        6
  •  -4
  •   user205666    14 年前

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

    # 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定义的$client;)” 但几乎可以肯定 不是 你在找什么!在程序早期确保$client有一些定义要容易得多(例如 $Client=“”; )还要注意Kaklon关于 !=
    2. 如果(x)材料其他 不是有效的Perl。你可以这样做: 如果(x)材料其他1; 但这有点像在求问题,因为真正的问题是对变量的测试,而不是一个else子句。
    3. 对不起,没有线索-我想问题出在别的地方。

    我也赞同Kinopiko的建议 “使用严格”; 在程序开始时。这意味着您使用的任何$variable@都必须预先定义为 “我的$varable;我的@that;我的%you;” 这看起来像是更多的工作,但这比在代码中处理未定义变量和已定义变量的工作要少。这是个好习惯。

    注意 我的 变量只存在于定义它们的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.