为什么perl警告打开我的$fh,$文件缺少括号?
这是我第一天来perl,我觉得这个警告很混乱.
它似乎 open FILE,$file; 工作正常. 出什么问题了 open my $fh,$file; 谢谢! #!/usr/bin/perl use strict; use warnings; sub grep_all { my $pattern = shift; while (my $file = shift) { open my $fh,$file; while (my $line = <$fh>) { if ($line =~ m/$pattern/) { print $line; } } } } grep_all @ARGV; 解决方法
我一直在黑客攻击Perl已经15年了,我承认这个警告让我刮伤了我一分钟,因为几乎每一个例子都要打开标准的Perl文档,几乎每一个Perl教程都是开放的,没有括号就像你写的一样.
您在第一天使用Perl写了这个问题,但是您已经启用了严格和警告pragmata!这是一个很好的开始. 假启动 一个简单而愚蠢的方法来“修复”警告是禁用所有警告.这将是一个可怕的举动!警告是为了帮助你. 无奈的镇压警告的方式是放弃了lexical filehandle,以赤字为借口 open FH,$file; 使用明确的括号打开 open(my $fh,$file); 使我的括号明确 open my($fh),$file; 使用外接括号 (open my $fh,$file); 或使用3参数 open my $fh,"<",$file; 我建议不要使用任何这些,因为它们都有严重的遗漏. 最好的方法 一般来说,沉默这个关于缺失括号的警告的最佳方法包括不添加括号! 始终检查是否打开成功,例如, open my $fh,$file or die "$0: open $file: $!"; 要禁用Perl的magic open并将$file视为文件的文字名称,在处理untrusted user input使用时 open my $fh,$file or die "$0: open $file: $!"; 是的,两者都封闭了警告,但是更重要的好处是您的程序处理不可避免的错误,而不是忽视它们,并且无论如何还是向前收费. 继续阅读以了解为什么你收到警告,有助于您提供下一个Perl程序,一些Perl理念,并建议您改进代码.最后,你会看到你的程序不需要显式调用打开! 写有用的错误信息 注意传递给 >抱怨的程序($0) 这些特殊变量在perlvar中有记录.现在就要将每个错误信息中包含这些重要信息的习惯现在开发出来 – 尽管不一定是用户看到的.拥有所有这些重要信息将在未来节省调试时间. 始终检查是否打开成功! 再次,始终检查打开和其他系统调用是否成功!否则,最终会出现奇怪的错误: $./mygrep pattern no-such-file Parentheses missing around "my" list at ./mygrep line 10. readline() on closed filehandle $fh at ./mygrep line 11. Perl的警告说明 在perldiag documentation,Perl的警告有进一步的解释,diagnostics pragma将会查看perl发出的任何警告的解释.使用你的代码,输出是
-Mdiagnostics命令行选项等效于使用诊断;在您的代码中,但如上所述运行它可临时启用诊断说明,而无需修改代码本身. 警告#2是因为没有这样的文件不存在,但你的代码无条件地从$fh读取. 令人困惑的是,你看到1号警告!这是我第一次记得看到它与打开的电话相关联. 5.10.1文档有52个例子用于涉及词法文件句柄,但只有两个与我的括号相同. 它好奇好奇: $perl -we 'open my $fh,$file' Name "main::file" used only once: possible typo at -e line 1. Use of uninitialized value $file in open at -e line 1. 括号丢失,那么警告在哪里? 然而,添加一个小分号警告失踪括号: $perl -we 'open my $fh,$file;' Parentheses missing around "my" list at -e line 1. Name "main::file" used only once: possible typo at -e line 1. Use of uninitialized value $file in open at -e line 1. 我们来看看perl的来源,看看警告来自哪里. $grep -rl 'Parentheses missing' . ./t/lib/warnings/op ./op.c ./pod/perl561delta.pod ./pod/perldiag.pod ./pod/perl56delta.pod
/* some heuristics to detect a potential error */ while (*s && (strchr(",tn",*s))) s++; while (1) { if (*s && strchr("@$%*",*s) && *++s && (isALNUM(*s) || UTF8_IS_CONTINUED(*s))) { s++; sigil = TRUE; while (*s && (isALNUM(*s) || UTF8_IS_CONTINUED(*s))) s++; while (*s && (strchr(",*s))) s++; } else break; } if (sigil && (*s == ';' || *s == '=')) { Perl_warner(aTHX_ packWARN(WARN_PARENTHESIS),"Parentheses missing around "%s" list",lex ? (PL_parser->in_my == KEY_our ? "our" : PL_parser->in_my == KEY_state ? "state" : "my") : "local"); } 注意第一行的注释.在My Life With Spam年,Mark Dominus写道:“当然,这是一种启发式的方式,这是一种说法不起作用的花哨的方法.”在这种情况下,启发式方法也不起作用,产生混乱的警告. 有条件的 if (sigil && (*s == ';' || *s == '=')) { 解释为什么perl -we’打开我的$fh,$文件’不警告,但是使用后缀分号.看看会发生什么类似但荒谬的代码: $perl -we 'open my $fh,$file =' Parentheses missing around "my" list at -e line 1. syntax error at -e line 1,at EOF Execution of -e aborted due to compilation errors. 我们得到警告! 3参数的开放案例不会发生警告,因为“<”防止sigil变成真实的,或者是... ...修饰符以钝的方式通过,因为或者令牌以除了以外的字符开始;或=. 警告的目的似乎是提供一个有用的提示,如何修复代码,否则会产生令人惊讶的结果, $perl -lwe 'my $foo,$bar = qw/ baz quux /; print $foo,$bar' Parentheses missing around "my" list at -e line 1. Useless use of a constant in void context at -e line 1. Use of uninitialized value $foo in print at -e line 1. quux 在这里,警告确实有意义,但是您发现的情况是启发式漏洞. 少即是多 如perlop文档中所述,Perl具有使写Unix-style filters容易的语法糖.
使用空文件句柄(也称为钻石操作符)使您的代码的行为像Unix grep实用程序. >过滤命令行上命名的每个文件的每一行,或 钻石运算符还处理至少一个您的代码没有的角落.在下面的注释中,该栏存在于输入中,但不出现在输出中. $cat 0 foo bar baz $./mygrep bar 0 Parentheses missing around "my" list at ./mygrep line 10. 继续阅读,看看钻石操作符如何提高可读性,表达经济性和正确性! 建议对您的代码进行改进 #! /usr/bin/env perl use strict; use warnings; die "Usage: $0 pattern [file ..]n" unless @ARGV >= 1; my $pattern = shift; my $compiled = eval { qr/$pattern/ }; die "$0: bad pattern ($pattern):n$@" unless $compiled; while (<>) { print if /$compiled/; } 而不是硬编码perl的路径,使用env来尊重用户的PATH. 不要盲目地假设用户至少在命令行上提供了一个模式,检查它是否存在或提供有用的使用指南. 因为你的模式生活在一个变量中,它可能会改变.这不是很深刻,但这意味着每次代码评估/ $pattern /,即每行输入时,都可能需要重新编译该模式.使用 $./mygrep ?foo ./mygrep: bad pattern (?foo): Quantifier follows nothing in regex; marked by <-- HERE in m/? <-- HERE foo/ at ./mygrep line 10. 主循环既成语又紧凑. $_特殊变量是许多Perl运算符的默认参数,明智的使用有助于强调实现的机制,而不是如何实现. 我希望这些建议有所帮助! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |