【问题标题】:redirecting stdin/stdout from exec'ed process to pipe in Perl将标准输入/标准输出从执行的进程重定向到 Perl 中的管道
【发布时间】:2013-08-20 03:43:03
【问题描述】:
我试图让已执行子进程中的 STDOUT/STDERR 通过 Perl 中的管道返回父进程。我所看到的最接近我想做的事情是:
http://forums.devshed.com/perl-programming-6/exec-and-redirecting-stdout-stderr-168501.html
以下是我正在尝试做的一个精简示例。我还尝试了上面链接的变体。我看不出我做错了什么......
#!/usr/bin/env perl
use strict ;
use warnings ;
my $cmd = "/usr/bin/who -a" ; # anything to stdout
pipe( READER, WRITER ) ;
my $child = fork() ;
if ( $child ) {
print "I am the parent: My pid = $$ junior = $child\n" ;
close( WRITER ) ;
my @output = <READER> ;
print @output ;
print "parent is DONE\n" ;
} else {
print "I am the child. My pid = $$\n" ;
close( READER ) ;
close( STDOUT );
close( STDERR );
*STDOUT = *WRITER ;
*STDERR = *WRITER ;
print WRITER "XXX ouput before exec....\n" ;
exec( $cmd ) or exit(1) ;
}
【问题讨论】:
标签:
perl
redirect
exec
pipe
stdout
【解决方案1】:
仅通过赋值来重定向文件描述符是不可能的。而是需要使用open,如perldoc -f open 中所述。在您的情况下,子代码如下所示:
print "I am the child. My pid = $$\n" ;
close( READER ) ;
open STDOUT, ">&", \*WRITER or die $!;
open STDERR, ">&", \*WRITER or die $!;
print WRITER "XXX ouput before exec....\n" ;
exec( $cmd ) or exit(1) ;
【解决方案2】:
Slaven Rezic 对您的代码为什么不起作用有正确的答案,但您也应该知道可以使用的快捷方式。特殊的 pipe+fork open READER, '-|' 为您完成了几乎所有的设置工作,创建了一个子进程,其 STDOUT 写入一个父进程可以使用 READER 读取的管道。这只剩下 STDERR 重定向让您手动执行。
代码的缩短版本如下所示:
my $child = open READER, '-|';
defined $child or die "pipe/fork: $!\n";
if ( $child ) {
print "I am the parent: My pid = $$ junior = $child\n" ;
my @output = <READER> ;
print @output ;
print "parent is DONE\n" ;
} else {
print "I am the child. My pid = $$\n" ;
open STDERR, '>&STDOUT';
print "XXX ouput before exec....\n" ;
exec( $cmd ) or exit(1) ;
}
【解决方案3】:
此代码是从子进程通过管道传输 STDOUT 和 STDERR 的另一种方式。
#!/usr/bin/env perl
use strict ;
use warnings;
my $cmd = "/usr/bin/who -a" ; # anything to stdout
pipe( READER, WRITER ) ;
my $child = fork() ;
if ( $child ) {
print "I am the parent: My pid = $$ junior = $child\n" ;
close( WRITER ) ;
my @output = <READER> ;
print @output ;
print "parent is DONE\n" ;
} else {
print "I am the child. My pid = $$\n" ;
close( READER ) ;
open(STDERR,">&", WRITER) or die "Cannot duplicate STDERR;
open(STDOUT,">&", WRITER) or die "cannot duplicate STDOUT";
print WRITER "XXX ouput before exec....\n" ;
exec( $cmd ) or exit(1) ;
}