IO::P ipe - close(<handle>) 不设置 $?



我的理解是,关闭IO::Pipe对象的句柄应该使用方法($fh->close)而不是内置方法(close($fh))来完成。

前几天,我出于习惯在一个IO::Pipe对象上搞砸并使用了内置的,该对象被打开到一个我预计会失败的命令。当$?为零时,我很惊讶,并且没有触发我的错误检查。

我意识到了我的错误。如果我使用内置的,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:

对我来说,内置导致管道关闭,但没有设置$?似乎很奇怪.谁能帮助解释这种差异?

谢谢!

如果您查看 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(幕后)后,它执行了等待:

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} 。

这回答了你的问题。

但令我惊讶的是,perl 似乎仍然在不设置 $? 通过核心关闭管道。

为什么会这样?它无法知道另一端的进程是一个孩子,更不用说程序应该等待的过程了。由于它没有理由打电话给waitpid$?不会设置。

事实上,我怀疑它是否在管道的另一端等待进程,

即使它愿意,因为我怀疑是否有一种方法可以在管道的另一端获取进程的 pid,因为实际上有可能在管道的另一端有多个进程。

IO::Pipe::close仅在使用 IO::P ipe "打开进程"时调用waitpid

同样,close仅在使用open"打开进程"时调用waitpid

使用一种方法"打开"的进程不能被另一种方法关闭。

事实证明,我的困惑源于一个有缺陷的假设,即消失的管道与完整的进程终止相吻合。情况似乎并非如此,因为该过程仍然可用于wait()

> perl -MIO::Pipe -le 'my $io = IO::Pipe->reader(q(false)); close($io); print $?; print wait(); print $?'
0
8857
256

最新更新