IO :: Pipe - close(<handle>)没有设置$?</handle>

时间:2013-10-29 21:56:25

标签: perl

我的理解是,关闭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: 。任何人都可以帮忙解释这种差异吗?

谢谢!

3 个答案:

答案 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