问题描述
我正在尝试通过 Capture::Tiny
获取失败时的命令输出,
#!/usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use Carp 'confess';
use Capture::Tiny 'capture';
sub execute {
my $cmd = shift;
my ($stdout,$stderr,$exit) = capture {
system( $cmd ); # the script dies here
};
if ($exit != 0) { # the script should die here
say "exit = $exit";
say "STDOUT = $stdout";
say "STDERR = $stderr";
confess "$cmd failed";
}
say "STDOUT = $stdout";
say "STDERR = $stderr";
say "exit code = $exit";
return 0
}
execute("ls fakedir");
但问题是当我执行脚本时,
con@V:~/Scripts$ perl execute.pl
"ls fakedir" unexpectedly returned exit value 2 at /home/con/perl5/perlbrew/perls/perl-5.32.0/lib/site_perl/5.32.0/Capture/Tiny.pm line 382.
我得到的只是退出值,它没有提供 fakedir
不存在的有价值的信息。也就是说,我只有在脚本成功时才得到 STDOUT 和 STDERR。
无论我使用 die
还是 confess
我都会遇到同样的问题 -> 脚本不打印输出 $stderr
和 $stdout
我已经按照 How do you capture stderr,stdout,and the exit code all at once,in Perl? 上的建议尝试了 IO::CaptureOutput
,这符合我的要求,但作者 https://metacpan.org/pod/IO::CaptureOutput 说“维护者不再推荐此模块 - 请参阅捕获: :微小的。”这很奇怪,IO::CaptureOutput 似乎工作得更好!
我怎样才能让这个脚本在 $stdout
、$stderr
和 $exit
中打印出忏悔?
解决方法
Capture::Tiny 工作正常。 system
正在引发错误,就好像 use autodie "system"
已打开一样。 Capture::Tiny 只捕获 STDOUT 和 STDERR,不会捕获错误。
您必须进行错误处理。你可以用一个 eval 块来捕获它。
my ($stdout,$stderr,$exit) = capture {
eval {
system( $cmd );
}
};
if (my $e = $@) { # the script should die here
# Can't get the system exit code from autodie.
#say "exit = $exit"
say "STDOUT = $stdout";
say "STDERR = $stderr";
confess "$cmd failed";
}
else {
say "STDOUT = $stdout";
say "STDERR = $stderr";
say "exit code = $exit";
return 0;
}
在这种特定情况下,您已经在做 autodie 所做的事情。只需在捕获块内关闭 autodie 就更简单了。
my ($stdout,$exit) = capture {
no autodie "system";
system( $cmd );
};
if ($exit) {
say "exit = $exit";
say "STDOUT = $stdout";
say "STDERR = $stderr";
# the script should die here
confess "$cmd failed";
}
else {
say "STDOUT = $stdout";
say "STDERR = $stderr";
say "exit code = $exit";
return 0;
}
或者,因为无论如何你都会出错,你可以让 autodie 来做它的事情。
my ($stdout,$exit) = capture {
system( $cmd );
};
say "STDOUT = $stdout";
say "STDERR = $stderr";
say "exit code = $exit";