的-Mdiagnostics
命令行选项是等效于在代码use diagnostics;
,但运行它如上暂时使诊断的解释,而不必修改您的代码本身。
警告#2是因为no-such-file
不存在,但您的代码无条件地从$fh
读取。
令人费解的是,你看到警告#1!这是第一次我记得曾经一起open
呼叫看到它的关联。该5.10.1文档中有52例的open
包括词法文件句柄使用,但其中只有有圆括号my
。
它变得奇妙而又奇妙:
$ 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哪位处理my
,our
,state
,并且local
- 包含下面的代码片段:
/* 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");
}
公告第一行的注释。在My Life With Spam,马克Dominus写道,“当然,这是一种启发式的,这是说,这是行不通的一个奇特的方式。”在这种情况下,启发式也不起作用并产生一个令人困惑的警告。
有条件
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 EOF
Execution of -e aborted due to compilation errors.
我们收到警告!因为"<"
阻止sigil
成为true,并且or die ...
修饰符以钝角条件通过调整,因为or
标记以;
或=
以外的其他字符开头,所以3个参数open
的情况不会发出警告。
警告的意图似乎是提供如何解决代码,否则会产生令人惊讶的结果有用的提示,例如,
$ 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
这里,警告确实是有意义的,但你发现的情况是启发式泄漏。
少即是多
Perl有这使得编写Unix-style filters容易的,因为perlop文档中解释语法糖。
的空文件句柄<>
是特殊的:它可以用来模拟的sed和awk行为。从<>
输入是无论是从标准输入,或在命令行上列出的每个文件。以下是它的工作原理:第一次对<>
进行评估时,将检查@ARGV
阵列,如果它是空的,则将$ARGV[0]
设置为"-"
,打开时会为您提供标准输入。然后将@ARGV
数组作为文件名列表进行处理。循环
while (<>) {
... # code for each line
}
相当于下面的Perl般的伪代码:
unshift(@ARGV, '-') unless @ARGV;
while ($ARGV = shift) {
open(ARGV, $ARGV);
while (<ARGV>) {
... # code for each line
}
}
使用空文件句柄(又称钻石操作)使你的代码的行为像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):\[email protected]" 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运算符的默认参数,而明智的使用有助于强调执行机制的方式,而不是实现的机制。
我希望这些建议帮助!
总是,*总是*,**总是**检查'open'是否成功! – 2011-04-08 14:55:47
用三个参数[打开](http://perldoc.perl.org/functions/open.html) – 2011-04-08 15:01:27