- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这是我接触 perl 的第一天,我发现这个警告非常令人困惑。
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 已经超过 15 年了,我承认这个警告让我摸不着头脑,因为几乎每个例子都调用 open
。在标准 Perl 文档和几乎所有现有的 Perl 教程中都包含 open
没有括号,就像你写的那样。
您在使用 Perl 的第一天就写了这个问题,但您已经启用了 strict
和 warnings
实用主义!这是一个很好的开始。
错误的开始
“修复”警告的一种简单但愚蠢的方法是禁用所有警告。这将是一个可怕的举动!警告旨在帮助您。
消除警告的幼稚方法是放弃 lexical filehandle赞成使用裸词的坏旧方式
open FH, $file;
open
中使用显式括号
open(my $fh, $file);
my
的括号明确
open my($fh), $file;
(open my $fh, $file);
open
.
open my $fh, "<", $file;
open
成功,例如,
open my $fh, $file or die "$0: open $file: $!";
$file
作为文件的字面名称——很重要,例如,在处理
untrusted user input 时-用
open my $fh, "<", $file or die "$0: open $file: $!";
open
。 !
die
的错误消息的重要组成部分:
$0
) "open $file"
) $!
) open
成功!
open
和其他系统调用成功!否则,您最终会遇到奇怪的错误:
$ ./mygrep pattern no-such-fileParentheses missing around "my" list at ./mygrep line 10.readline() on closed filehandle $fh at ./mygrep line 11.
Perl's warnings have further explanation in the perldiag documentation, and enabling the diagnostics pragma will look up explanations of any warning that perl emits. With your code, the output is
$ perl -Mdiagnostics ./mygrep pattern no-such-file
Parentheses missing around "my" list at./mygrep
line 10 (#1)
(W parenthesis) You said something likemy $foo, $bar = @_;
when you meant
my ($foo, $bar) = @_;
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.
The -Mdiagnostics
command-line option is equivalent to use diagnostics;
in your code, but running it as above temporarily enables diagnostic explanations without having to modify your code itself.
Warning #2 is because no-such-file
does not exist, but your code unconditionally reads from $fh
.
It's puzzling that you see warning #1 at all! This is the first time I recall ever seeing it in association with a call to open
. The 5.10.1 documentation has 52 example uses of open
involving lexical filehandles, but only two of them have parentheses with my
.
It gets curiouser and curiouser:
$ 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.
Parentheses are missing, so where's the warning?!
Adding one little semicolon, however, does warn about missing parentheses:
$ 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.
Let's look in perl's source to see where the warning comes from.
$ grep -rl 'Parentheses missing' ../t/lib/warnings/op./op.c./pod/perl561delta.pod./pod/perldiag.pod./pod/perl56delta.pod
Perl_localize
in op.c—which handles my
, our
, state
, and local
—contains the following snippet:
/* 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(", \t\n", *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");
}
if (sigil && (*s == ';' || *s == '=')) {
perl -we 'open my $fh, $file'
不警告,但带有尾随分号。观察类似但无意义的代码会发生什么:
$ perl -we 'open my $fh, $file ='Parentheses missing around "my" list at -e line 1.syntax error at -e line 1, at EOFExecution of -e aborted due to compilation errors.
We get the warning! The 3-argument open
case doesn't warn because "<"
prevents sigil
from becoming true, and the or die ...
modifier passes muster, in obtuse terms, because the or
token begins with a character other than ;
or =
.
The intent of the warning appears to be providing a helpful hint for how to fix code that will otherwise produce surprising results, e.g.,
$ 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
Here, the warning does make sense, but the case you found is a leak in the heuristic.
Perl has syntactic sugar that makes writing Unix-style filters easy, as explained in the perlop documentation.
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 loopwhile (<>) {
... # code for each line
}is equivalent to the following Perl-like pseudo code:
unshift(@ARGV, '-') unless @ARGV;
while ($ARGV = shift) {
open(ARGV, $ARGV);
while (<ARGV>) {
... # code for each line
}
}
Using the null filehandle (also known as the diamond operator) makes your code behave like the Unix grep utility.
The diamond operator also handles at least one corner case that your code doesn't. Note below that bar is present in the input but doesn't appear in the output.
$ cat 0foobarbaz$ ./mygrep bar 0Parentheses missing around "my" list at ./mygrep line 10.
Keep reading to see how the diamond operator improves readability, economy of expression, and correctness!
#! /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
尊重用户的路径。
/$pattern/
时可能需要重新编译模式。 ,即对于每一行输入。使用
qr//
避免了这种浪费,还提供了一个机会来检查用户在命令行上提供的模式是否是有效的正则表达式。
$_
特殊变量是许多 Perl 运算符的默认参数,明智的使用有助于强调实现机制的内容而不是方式。
关于perl - 为什么 perl 警告打开我的 $fh, $file 缺少括号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5596874/
如果我的 Perl 程序使用 Perl 模块,它将如何确定在哪里可以找到包含模块代码的文件? 例如,如果程序包含: use MyModule1; # Example 1 us
我在一个文件中有一些不同格式的数字:8.3、0.001、9e-18。我正在寻找一种简单的方法来读取它们并存储它们而不会损失任何精度。这在 AWK 中很容易,但在 Perl 中是如何完成的呢?我只愿意使
我在一个文件中有一些不同格式的数字:8.3、0.001、9e-18。我正在寻找一种简单的方法来读取它们并存储它们而不会损失任何精度。这在 AWK 中很容易,但在 Perl 中是如何完成的呢?我只愿意使
我正在自学 Perl,并且在我的 Windows 8 64 位系统上安装了 Strawberry。 Strawberry 命令行似乎工作正常,我在 C 驱动器上的 Strawberry 文件夹中创建了
我在 Perl 模块 IO::Socket::SSL 中发现了一个错误,我可能会修复它,但是,我担心测试修复。我从 Debian 下载了源码包(因为我打算为它制作一个 Debian 包或补丁)并查看了
我有一个 perl 文件,它使用了两个 perl 模块 A.pm 和 B.pm。 但是在 B.pm 中我需要调用 A.pm 的子程序。即使我在 A.pm 中使用并尝试使用它,我仍然遇到未定义的错误。
有没有办法在 Perl 运行时加载整个模块?我原以为我用 autouse 找到了一个很好的解决方案,但以下代码无法编译: package tryAutouse2; use autouse 'tryAu
过去,我编写过许多 perl 模块,以及不止一些独立的 perl 程序,但我之前从未发布过多文件 perl 程序。 我有一个几乎处于 beta 阶段的 perl 程序,它将被开源发布。它需要一些数据文
我有 1 个 perl 脚本,我们在其中编写了几个子例程。例子: # Try_1.pl main(); sub main{ --- --- check(); } check { -- --} 现在,
似乎 CPAN 上的一些(很多?)模块部分是使用 XS 在 C 中实现的,如果需要,可以回退到纯 perl 实现。虽然这很聪明,但它显然会损害性能,我想知道它是否会发生,以便我可以解决问题。 有没有一
我对 perl 很陌生。我希望我可以从 perl 安装一些软件包,我这样做是这样的: perl -MCPAN -e 'install VM::EC2' 我猜它由于依赖而失败,它显示: Result:
给定一个 Perl 包 Foo.pm,例如 package Foo; use strict; sub bar { # some code here } sub baz { # more
我有一个用 Perl 编写的测试生成器。它生成连接到模拟器的测试。这些测试本身是用 Perl 编写的,并通过其 API 连接到模拟器。我希望生成的代码是人类可读的,这意味着我希望它能够正确缩进和格式化
我正在学习 Perl,非常新的用户。我可以知道这些 Perl 代码之间有什么区别吗? #!/usr/bin/perl & #!/usr/bin/perl -w 最佳答案 那不是 perl 代码,它是
我不认为这是一个重复的问题。这专门针对 Perl 模块附带的脚本。 通常,在安装多个 Perl 版本时,您可以将 perl 可执行文件标记为版本号 (perl5.32),这样它们就可以在 /whate
我有一个在文件中使用 Blowfish 加密的程序和第二个 perl 程序,它提示输入用于将其解密为字符串的密码,我希望不必将解密的源代码写入硬盘驱动器,尽管将它放在内存中并不是真正的问题,因为运行程
有没有人为 Perl 中的惰性求值列表找到了一个好的解决方案?我尝试了很多方法来改变类似的东西 for my $item ( map { ... } @list ) { } 进入懒惰的评估——例如,通
我安装了多个版本的 Perl。 我已经指定了要使用的版本。但是为了验证,我想从 .pl 脚本本身输出 Perl 的版本。 这可能吗? 在 Perl 脚本中解析“perl --version”的输出似乎
人们还经常问“我怎样才能编译 Perl?”而他们真正想要的是创建一个可以在机器上运行的可执行文件,即使他们没有安装 Perl。 我知道有几种解决方案: perl2exe靛蓝之星 它是商业的。我从未尝试
关闭。这个问题是opinion-based .它目前不接受答案。 想改进这个问题?更新问题,以便 editing this post 可以用事实和引用来回答它. 8年前关闭。 Improve this
我是一名优秀的程序员,十分优秀!