Parentheses missing around “my” list at ./grep.pl line 10.
它似乎
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写了这个问题,但是您已经启用了严格和警告pragmata!这是一个很好的开始.
假启动
一个简单而愚蠢的方法来“修复”警告是禁用所有警告.这将是一个可怕的举动!警告是为了帮助你.
无奈的镇压警告的方式是放弃了lexical filehandle,以赤字为借口
open FH,$file;
使用明确的括号打开
open(my $fh,$file);
使我的括号明确
open my($fh),$file;
使用外接括号
(open my $fh,$file);
或使用3参数open
.
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发出的任何警告的解释.使用你的代码,输出是
$perl -Mdiagnostics ./mygrep pattern no-such-file
Parentheses missing around “my” list at./mygrep
line 10 (#1)
(W parenthesis) You said something like06008
when you meant
06009
Remember that
my
,our
,local
andstate
bind tighter than comma.readline() on closed filehandle
$fh
at./mygrep
line 11 (#2)
(W closed) The filehandle you’re reading from got itself closed sometime before now. Check your control flow.
-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
Perl_localize
in op.c–处理我的,我们的,状态的和本地的 – 包含以下代码段:
/* some heuristics to detect a potential error */ while (*s && (strchr(",\t\n",*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容易的语法糖.
The null filehandle
<>
is special: it can be used to emulate the behavior of sed and awk. Input from<>
comes either from standard input,or from each file listed on the command line. Here’s how it works: the first time<>
is evaluated,the@ARGV
array is checked,and if it is empty,$ARGV[0]
is set to"-"
,which when opened gives you standard input. The@ARGV
array is then processed as a list of filenames. The loop060017
is equivalent to the following Perl-like pseudo code:
060018
使用空文件句柄(也称为钻石操作符)使您的代码的行为像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 /,即每行输入时,都可能需要重新编译该模式.使用qr//
避免了这种浪费,并且还提供了一个机会来检查用户在命令行中提供的模式是否是有效的正则表达式.
$./mygrep ?foo ./mygrep: bad pattern (?foo): Quantifier follows nothing in regex; marked by <-- HERE in m/? <-- HERE foo/ at ./mygrep line 10.
主循环既成语又紧凑. $_特殊变量是许多Perl运算符的默认参数,明智的使用有助于强调实现的机制,而不是如何实现.
我希望这些建议有所帮助!