我正在使用下面的脚本添加两个文件,但它间歇性地添加失败,没有错误输出。
(my $file1, my $file2) = @ARGV;
open(FILE1, ">>$file1");
open(FILE2, "<$file2");
while ( <FILE2> ) {
print FILE1 $_;
}
close(FILE2);
close(FILE1);
上面的代码有问题吗?
答案 0 :(得分:7)
您的代码的主要问题是它包含许多可能会失败的操作,但您没有检查错误,因此,如果失败,程序将以静默方式继续进行操作。
代码中可能会失败的三个函数是open
,print
和close
。在每种情况下,该函数都会在成功或失败时返回一个真值,将返回一个假值,还将失败消息存储在特殊的全局变量$!
中。
您写了:
open(FILE1,">>$file1");
最好写成:
open(my $out, '>>', $file1) || die "open(>>$file1): $!";
或者您可以使用较低优先级的or
运算符并跳过括号:
open my $out, '>>', $file1 or die "open(>>$file1): $!";
您可以简单地调用die $!
,但这会给您类似Permission denied
的错误消息,并且不会告诉您哪个操作失败了(尽管die
会在失败的位置添加行号发生)。有时,失败是由于以下事实:包含文件名的变量中包含意外内容-因此,将其打印出来也是一种好习惯。
您的代码包括一些相当旧的样式,因此我用词法范围的FILE1
替换了旧的$out
全局样式。我还使用了3参数形式的open,从安全角度来看,这是一个更好的主意。
print
调用也可能失败(例如:如果磁盘已装满)。这种可能性较小,并且经常忽略检查print
的返回值。 close
调用也可能失败(例如:在关闭文件句柄之前,输出缓冲区可能不会刷新,然后类似磁盘已满的情况可能会触发失败)。
记住在所有I / O函数调用的末尾添加or die "... $!"
有点乏味,因此更好的方法是在您的开始时将autodie
杂注添加到样板中脚本。然后,您可以省略显式错误检查,autodie
模块将为您生成消息:
use strict;
use warnings;
use autodie;
my($file1, $file2) = @ARGV;
open my $out, '>>', $file1;
open my $in, '<', $file2;
while (<$in>) {
print $out $_;
}
close($in);
close($out);
来自autodie的典型消息可能是:
Can't open '/etc/shadow' for reading: 'Permission denied' at ./ptst.pl line 8
这将告诉您哪个操作失败,参数是什么以及失败的原因。因此,通过使用autodie
,您会得到很好的错误消息,而工作量更少。
答案 1 :(得分:0)
尝试使用此版本以获取错误消息:
open(FILE1,">>", $file1) or die $!;
open(FILE2, "<", $file2) or die $!;