如何在Perl中读取外部命令的错误输出?
作为大型Perl程序的一部分,我将对照参考文件检查文件夹中输入文件的如何在Perl中读取外部命令的错误输出?,perl,backticks,Perl,Backticks,作为大型Perl程序的一部分,我将对照参考文件检查文件夹中输入文件的diff命令的输出,其中空白输出(匹配)是通过的结果,而diff的任何输出都是失败的结果 问题是,如果目标文件夹缺少预期的文件数,则异常diff throws不会作为输出出现,从而创建错误的传递 输出示例: diff: /testfolder/Test-02/test-output.2: No such file or directory 测试-01:通过 测试-02:通过 守则如下: $command = "(diff ca
diff
命令的输出,其中空白输出(匹配)是通过的结果,而diff的任何输出都是失败的结果
问题是,如果目标文件夹缺少预期的文件数,则异常diff throws不会作为输出出现,从而创建错误的传递
输出示例:
diff: /testfolder/Test-02/test-output.2: No such file or directory
测试-01:通过
测试-02:通过
守则如下:
$command = "(diff call on 2 files)";
my @output = `$command`;
print "Test-02: ";
$toPrint = "PASS";
foreach my $x (@output) {
if ($x =~ /./) {
$toPrint = "FAIL";
}
}
如果diff
调用有任何输出,这是一个很快就会失败的黑客作业。是否有方法检查在backticks
中调用的命令引发的异常?检查。如果设置为0,则没有信号,程序返回的代码也为零。那可能是你想要的
在这种情况下,您甚至可以使用并检查其返回值是否为零,同时将stdout和stderr重定向到/dev/null。程序本身不能抛出“异常”,但它们可以返回非零错误代码。您可以使用$?:
$toPrint = "FAIL" if $?;
(将这一行添加到测试
@output
的循环之前)下面列出了一系列有趣的方法,可以使用backticks命令的输出。您必须向下滚动到或搜索“qx/STRING/”(不带引号)您还可以使用“diff-d”的输出进行演练,这将使您的代码更易于阅读
foreach(`diff-d$args`){
如果(/^Only in/){
做什么都行;
}
}
您还可以:
my @output = `$command 2>\&1`;
假设差异错误最终出现在STDERR上,如果您希望能够检查或记录错误,我建议使用CPAN模块Capture::Tiny:
use Capture::Tiny 'capture';
my ($out, $err) = capture { system($command) };
这类似于backticks,但分别给出STDOUT和STDERR
运行外部命令有三种基本方式:
system $cmd; # using system()
$output = `$cmd`; # using backticks (``)
open (PIPE, "cmd |"); # using open()
使用system(),STDOUT和STDERR将与脚本的STDOUT和STDERR位于同一位置,除非system()命令重定向它们。Backticks和open()仅读取命令的标准输出
您还可以使用IPC::open3中的open3()函数。Benjamin Goldberg提供了一些示例代码:
要捕获程序的标准输出,但放弃其标准输出,请执行以下操作:
use IPC::Open3;
use File::Spec;
use Symbol qw(gensym);
open(NULL, ">", File::Spec->devnull);
my $pid = open3(gensym, \*PH, ">&NULL", "cmd");
while( <PH> ) { }
waitpid($pid, 0);
$output = `cmd 2>/dev/null`; # either with backticks
$pid = open(PH, "cmd 2>/dev/null |"); # or with an open pipe
while (<PH>) { } # plus a read
也可以使用Bourne shell文件描述符重定向:
$output = `$cmd 2>some_file`;
open (PIPE, "cmd 2>some_file |");
您还可以使用文件描述符重定向使STDERR成为STDOUT的副本:
$output = `$cmd 2>&1`;
open (PIPE, "cmd 2>&1 |");
请注意,您不能简单地在Perl程序中打开STDERR作为STDOUT的dup,并避免调用shell来执行重定向。这不起作用:
open(STDERR, ">&STDOUT");
$alloutput = `cmd args`; # stderr still escapes
这会失败,因为open()使STDERR转到在open()时STDOUT要去的地方。然后,反勾号使STDOUT转到字符串,但不要更改STDERR(它仍然转到旧的STDOUT)
请注意,您必须在backticks中使用伯恩shell(sh(1))重定向语法,而不是csh(1)!关于Perl的system()和backtick以及pipe opens为什么都使用Bourne shell的详细信息,请参阅中“远比您想知道的多”集合中的VS/csh.whynot文章。要同时捕获命令的STDERR和STDOUT,请执行以下操作:
$output = `cmd 2>&1`; # either with backticks
$pid = open(PH, "cmd 2>&1 |"); # or with an open pipe
while (<PH>) { } # plus a read
在所有这些示例中,排序都很重要。这是因为shell严格按照从左到右的顺序处理文件描述符重定向
system("prog args 1>tmpfile 2>&1");
system("prog args 2>&1 1>tmpfile");
第一个命令将标准输出和标准错误发送到临时文件。第二个命令只发送那里的旧标准输出,旧标准错误显示在旧标准输出上。+1。重定向到/dev/null也是一个好主意,不过使用-q选项进行diff会更快,因为它首先避免了生成大部分输出。添加了几乎完全相同的行,所有内容都立即进入正确的工作行为。
$output = `$cmd 2>&1`;
open (PIPE, "cmd 2>&1 |");
open(STDERR, ">&STDOUT");
$alloutput = `cmd args`; # stderr still escapes
$output = `cmd 2>&1`; # either with backticks
$pid = open(PH, "cmd 2>&1 |"); # or with an open pipe
while (<PH>) { } # plus a read
$output = `cmd 2>/dev/null`; # either with backticks
$pid = open(PH, "cmd 2>/dev/null |"); # or with an open pipe
while (<PH>) { } # plus a read
$output = `cmd 2>&1 1>/dev/null`; # either with backticks
$pid = open(PH, "cmd 2>&1 1>/dev/null |"); # or with an open pipe
while (<PH>) { } # plus a read
$output = `cmd 3>&1 1>&2 2>&3 3>&-`; # either with backticks
$pid = open(PH, "cmd 3>&1 1>&2 2>&3 3>&-|");# or with an open pipe
while (<PH>) { } # plus a read
system("program args 1>program.stdout 2>program.stderr");
system("prog args 1>tmpfile 2>&1");
system("prog args 2>&1 1>tmpfile");