作为一般策略,我避免使用后排,而是依赖于捕捉:微小和系统调用。
my ( $stdout, $stderr, @results ) = capture { system($command) };然而,当我在Capture::Tiny下使用之前从未见过的异常时,我只是遇到了HTML::Mason内部的一个异常。
Error from open(GLOB(0x555ef4527090), >&-1): Invalid argument at /usr/share/perl5/vendor_perl/Capture/Tiny.pm line 107.
Capture::Tiny::_open(GLOB(0x555ef4527090), ">\\x{26}-1") called at /usr/share/perl5/vendor_perl/Capture/Tiny.pm line 194
Capture::Tiny::_open_std(HASH(0x555ec25b12b8)) called at /usr/share/perl5/vendor_perl/Capture/Tiny.pm line 391
Capture::Tiny::_capture_tee(1, 1, 0, 0, CODE(0x555f05d5ce70)) called at InternalModule.pm line 41
...
InternalModule.pm called at /.../apache/htdocs/autohandler line 84
HTML::Mason::Commands::__ANON__() called at /usr/share/perl5/vendor_perl/HTML/Mason/Component.pm line 135这是一个遗留系统,所以模块版本有点旧。
在Capture::Tiny中执行一些内部操作显示,此方法正在引发异常
sub _open {
open $_[0], $_[1] or Carp::confess "Error from open(" . join(q{, }, @_) . "): $!"; # Line 107
# _debug( "# open " . join( ", " , map { defined $_ ? _name($_) : 'undef' } @_ ) . " as " . fileno( $_[0] ) . "\n" );
}具体来说,调用_open并导致异常的是STDOUT的开放:
# In some cases we open all (prior to forking) and in others we only open
# the output handles (setting up redirection)
sub _open_std {
my ($handles) = @_;
_open \*STDIN, "<&" . fileno $handles->{stdin} if defined $handles->{stdin};
_open \*STDOUT, ">&" . fileno $handles->{stdout} if defined $handles->{stdout}; # Line 194
_open \*STDERR, ">&" . fileno $handles->{stderr} if defined $handles->{stderr};
}我尝试过本地化*STDOUT,尽管看起来Capture::Tiny已经这样做了。
现在我的结论是,我应该用这样的解决方案
system("program args 1>program.stdout 2>program.stderr");关于Capture::Tiny,我还缺少什么东西让它在Mason下工作吗?
发布于 2021-08-18 03:08:21
在后台使用Capture::Tiny和system调用有几个好处
但是,在本例中,我决定编写备份方法,以防Capture::Tiny在任何特定环境中不可用。如果不是,那么我们将只输出这些流来临时文件,并摄入它们的后缀。
# Capture::Tiny has an incompatibility with Mason. Therefore we simply need to
# detect if it's safe to use, and if not we should do another mechanism for
# capturing the results.
state $is_safe_to_use_capture_tiny = eval {
capture sub { };
1;
};
my ( $stdout, $stderr, @result );
if ($is_safe_to_use_capture_tiny) {
( $stdout, $stderr, @result ) = capture { system($command) };
} else {
# Backup equivalent to Capture::Tiny
# There is some risk to this approach, because we are choosing to cache
# the stdout and stderr results to a file temporarily. If these results
# of the system call include sensitive information, then it would exist on
# disk momentarily.
# However, given this is just a backup method that is only needed in
# the case of system calls under Mason which is front end servers that do not
# have access to sensitive information, it's an okay sacrifice.
my $stdout_file = tempfile();
my $stderr_file = tempfile();
@result = system(qq{$command 1>$stdout_file 2>$stderr_file});
$stdout = $stdout_file->exists ? $stdout_file->slurp : '';
$stderr = $stderr_file->exists ? $stderr_file->slurp : '';
}https://stackoverflow.com/questions/68810780
复制相似问题