【发布时间】:2019-03-25 12:50:05
【问题描述】:
我正在尝试捕获我的 perl 代码从 print 和类似语句以及外部命令生成的输出。
由于设计限制,我无法使用 Capture::Tiny 之类的解决方案。我需要在生成后立即将输出转发到缓冲区变量,并且我需要能够区分 STDOUT 和 STDERR。理想情况下,外部命令的解决方案基本上可以像系统一样工作,除了能够捕获 STDOUT 和 STDERR 而不是打印它们。
我的代码应该是:
- 保存旧的 STDOUT/STDERR 文件句柄。
- 为 STDERR 和 STDOUT 创建一个新的。
- 将所有输出重定向到此位置。
- 打印几样东西。
- 恢复旧的文件句柄。
- 对捕获的输出做一些事情,例如打印出来。
但是,我无法捕获从外部命令生成的输出。我不能用IPC::Run3 和IPC::Open3 来做。
#!/usr/bin/perl -CSDAL
use warnings;
use strict;
use IPC::Open3;
#use IPC::Run3;
# Save old filehandles
open(my $oldout, ">&STDOUT") or die "Can't dup STDOUT: $!";
open(my $olderr, ">&STDERR") or die "Can't dup STDERR: $!";
my $buffer = "";
close(STDOUT);
close(STDERR);
open(STDOUT, '>', \$buffer) or die "Can't redirect STDOUT: $!";
*STDERR = *STDOUT; # In this example STDOUT and STDERR are printed to the same buffer.
print "1: Test\n";
#run3 ["date"], undef, \*STDOUT, \*STDERR; # This doesn't work as expected
my $pid = open3("<&STDIN", ">&STDOUT", ">&STDERR", "date");
waitpid($pid,0); # Nor does this.
print STDERR "2: Test\n";
open(STDOUT, ">&", $oldout) or die "Can't dup \$oldout: $!";
open(STDERR, ">&", $olderr) or die "Can't dup \$olderr: $!";
print "Restored!\n";
print $buffer;
预期结果:
Restored!
1: Test
Mo 25. Mär 13:44:53 CET 2019
2: Test
实际结果:
Restored!
1: Test
2: Test
【问题讨论】:
-
也许
open3无法处理字符串缓冲区句柄?为什么不对open3调用使用常规文件句柄? -
使用
eval我可以得到 run3 语句的错误消息:Error: run3(): Invalid argument redirecting STDOUT at /root/test_io.pl line 25.这对我没有帮助。如果不重新分配STDOUT和STDERR,代码将按预期工作。我在这里有点茫然。 -
@HåkonHægland 我尽量避免这种情况,因为我不想要数百个临时文件。
-
您能否为我澄清/确认——您想简单地说,重定向标准输出和标准错误(分别),用于来自程序和来自外部命令的打印吗?就是这样,重定向流?这是相当简单的,在几个方面。 (必须是缓冲区(变量)而不是文件吗?)