7

对于我即将推出的 PulseAudio 库,我想重定向STDERRSTDOUT/dev/null逻辑上这样做,

sub _exec {
    open (*STDERR, '>', '/dev/null');    
    open (*STDOUT, '>', '/dev/null');    
    CORE::system('pacmd', @_ ) or die $?;

但是,这仍然输出到术语....

sub _exec {
    local ( *STDERR, *STDOUT );
    open (*STDERR, '>', '/dev/null');    
    open (*STDOUT, '>', '/dev/null');    
    CORE::system('pacmd', @_ ) or die $?;

这给我留下了两个问题

  1. 首先,为什么我会遇到我所看到的行为?
  2. 其次,是否有更有效的方法不涉及存储旧值并替换它?
4

1 回答 1

9

孩子写入 fd 1 和 2,但您没有更改 fd 1 和 2。您只是用 fd 3 和 4(孩子不关心的东西)创建了新的 Perl 变量(孩子一无所知)。

这是实现您想要的一种方法:

use IPC::Open3 qw( open3 );

sub _exec {
    open(local *CHILD_STDIN,  '<', '/dev/null') or die $!;
    open(local *CHILD_STDOUT, '>', '/dev/null') or die $!;
    my $pid = open3(
        '<&CHILD_STDIN',
        '>&CHILD_STDOUT',
        undef,  # 2>&1
        'pacmd', @_,
    );
    waitpid($pid, 0);
    die $! if $? == -1;
    die &? if $?;
}

open3水平很低,但比自己做的水平要高得多*。IPC::RunIPC::Run3甚至更高级别。



* — 它负责将句柄分叉并分配给正确的文件描述符。它处理错误检查,包括使子进程中的预exec错误看起来像是启动失败,而不是来自已执行程序的错误。

于 2012-12-12T05:43:16.617 回答