If you try to read from the child’s stdout writer and their stderr
writer,you’ll have problems with blocking,which means you’ll want to
use select() or the IO::Select,which means you’d best use sysread()
instead of readline() for normal stuff.This is very dangerous,as you may block forever. It assumes it’s
@H_502_15@
going to talk to something like bc,both writing to it and reading
from it. This is presumably safe because you “know” that commands like
bc will read a line at a time and output a line at a time. Programs
like sort that read their entire input stream first,however,are
quite apt to cause deadlock.所以我试过open3希望知道更好.这是第一次尝试:
sub hung_execute { my($cmd) = @_; print "[COMMAND]: $cmd\n"; my $pid = open3(my $in,my $out,my $err = gensym(),$cmd); print "[PID]: $pid\n"; waitpid($pid,0); if(<$err>) { print "[ERROR] : $_" while(<$err>); die; } print "[OUTPUT]: $_" while (<$out>); }有趣的是,我必须在这里初始化$err.
无论如何,这只是挂起,当我执行(“sort $some_file”);因为$some_file是包含4096个字符(我的机器的限制)的文本文件.
然后我查看了this FAQ,下面是我的新版本的执行:
sub good_execute { my($cmd) = @_; print "[COMMAND]: $cmd\n"; my $in = gensym(); #--------------------------------------------------- # using $in,$out doesn't work. it expects a glob? local *OUT = IO::File->new_tmpfile; local *ERR = IO::File->new_tmpfile; my $pid = open3($in,">&OUT",">&ERR",0); seek $_,0 for \*OUT,\*ERR; if(<ERR>) { print "[ERROR] : $_" while(<ERR>); die; } print "[OUTPUT]: $_" while (<OUT>); }排序命令现在执行正常,但是我不知道为什么.
[更新]阅读@ tchrist的答案后,我读了IO :: Select,经过一些更多的搜索,已经提出了这个版本的执行:
sub good_execute { my($cmd) = @_; print "[COMMAND]: $cmd\n"; my $pid = open3(my $in,$cmd); print "[PID]: $pid\n"; my $sel = new IO::Select; $sel->add($out,$err); while(my @fhs = $sel->can_read) { foreach my $fh (@fhs) { my $line = <$fh>; unless(defined $line) { $sel->remove($fh); next; } if($fh == $out) { print "[OUTPUT]: $line"; }elsif($fh == $err) { print "[ERROR] : $line"; }else{ die "[ERROR]: This should never execute!"; } } } waitpid($pid,0); }这是正常的,现在有一些事情变得更加清晰.但整体情况还是有点朦胧.
所以我的问题是:
> hung_execute有什么问题?
>我猜good_execute的作品是因为>&在open3调用.但为什么和如何呢?
>此外,当我使用词法变量(我的$out而不是OUT)来处理文件句柄时,good_execute没有工作.它给出了这个错误:open3:open(GLOB(0x610920),&& main :: OUT)Failed:无效的参数.为什么这样?
>似乎只有一个文件句柄可以在给定的时间写入,如果我丢弃持有该资源的句柄,其他句柄将继续等待.我以前认为STDERR和STDOUT是独立的流,并没有共享任何资源.我想我的理解在这里有点有缺陷.请给我一些指针.
解决方法
你也有其他错误.你不能以这种方式测试句柄上的输出,因为你刚刚做了一个阻塞的readline并抛弃了它的结果.此外,如果您尝试在stdout之前读取所有stderr,并且如果在stdout上存在多个输出管道缓冲区,那么您的孩子会阻止写入stdout,同时阻止其从stderr读取.
你真的必须使用select,或者IO :: Select来做到这一点.只有当该句柄上有输出可用时,才能从句柄中读取,除非您非常幸运,否则您不得将缓冲的调用与select混合使用.