我的理解是,关闭IO::Pipe
对象的句柄应该使用方法($fh->close
)而不是内置的(close($fh)
)。
前几天我愚蠢地使用了IO::Pipe
对象的内置习惯,这个对象被打开了一个我预期失败的命令。 <{1}}为零时,我感到很惊讶,我的错误检查没有被触发。
我意识到自己的错误。如果我使用内置功能,则$?
无法执行IO:Pipe
,无法设置waitpid()
。但令我惊讶的是,perl似乎仍未关闭管道,而没有通过核心设置$?
。
我编写了一个小测试脚本来表明我的意思:
$?
使用该方法时,它显示管道在关闭后消失,use 5.012;
use warnings;
use IO::Pipe;
say 'init pipes:';
pipes();
my $fh = IO::Pipe->reader(q(false));
say 'post open pipes:';
pipes();
say 'return: ' . $fh->close;
#say 'return: ' . close($fh);
say 'status: ' . $?;
say q();
say 'post close pipes:';
pipes();
sub pipes
{
for my $fd ( glob("/proc/self/fd/*") )
{
say readlink($fd) if -p $fd;
}
say q();
}
按预期设置:
$?
而且,当使用内置它时,它似乎也会关闭管道,但是没有设置init pipes:
post open pipes:
pipe:[992006]
return: 1
status: 256
post close pipes:
:
$?
对我来说,内置导致管道闭包似乎很奇怪,但是没有设置init pipes:
post open pipes:
pipe:[952618]
return: 1
status: 0
post close pipes:
。任何人都可以帮忙解释这种差异吗?
谢谢!
答案 0 :(得分:2)
如果您查看IO::Handle
的代码(其中IO::Pipe::End
是子类),您将看到以下内容:
sub close {
@_ == 1 or croak 'usage: $io->close()';
my($io) = @_;
close($io);
}
看起来$fh->close
只是调用close $fh
。当然,我们不应该偷看幕后。
我们可以在IO::Pipe
执行close $fh
(幕后)之后看到它然后执行waitpid:
package IO::Pipe::End;
our(@ISA);
@ISA = qw(IO::Handle);
sub close {
my $fh = shift;
my $r = $fh->SUPER::close(@_); # <-- This just calls a CORE::close
waitpid(${*$fh}{'io_pipe_pid'},0)
if(defined ${*$fh}{'io_pipe_pid'});
$r;
}
同样有趣的是来自近距离的Perldoc:
如果文件句柄来自管道打开,则如果其中一个其他系统调用失败或其程序以非零状态退出,则close返回false。如果唯一的问题是程序退出非零,$!将被设置为0。
关闭管道还会等待管道上执行的流程退出 - 如果您希望查看管道的输出
之后 - 并隐式放置该命令的退出状态值 进入$?和$ {^ CHILD_ERROR_NATIVE}。
那就回答你的问题。
答案 1 :(得分:1)
但令我惊讶的是,perl似乎仍然在没有设置$的情况下关闭管道?通过核心。
为什么会这样?它无法知道另一端的进程是否为子进程,更不用说程序应该等待的进程。由于没有理由致电waitpid
,$?
不会被设置。
事实上,我怀疑它等待管道另一端的过程,即使它想要,因为我怀疑有一种方法可以在管道的另一端获得过程的pid,因为它实际上是可能在管道的另一端有多个进程。
当IO :: Pipe用于“打开进程”时, IO::Pipe::close
仅调用waitpid
。
同样,close
仅在waitpid
用于“打开流程”时调用open
。
使用一种方法“打开”的过程不能被另一种方法关闭。
答案 2 :(得分:0)
事实证明,我的困惑源于一个有缺陷的假设,即消失的管道与完整的过程终止同时发生。情况似乎并非如此,因为此过程仍适用于wait()
。
> perl -MIO::Pipe -le 'my $io = IO::Pipe->reader(q(false)); close($io); print $?; print wait(); print $?'
0
8857
256