为什么本地不在STDERR和STDOUT上工作?

Eva*_*oll 3 perl redirect stdout stderr

对于我即将推出的PulseAudio库,我想重定向STDERRSTDOUT/dev/null逻辑上对此工作,

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

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

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

这让我有两个问题

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

ike*_*ami 5

孩子写入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 $?;
}
Run Code Online (Sandbox Code Playgroud)

open3是相当低的水平,但它远远高于自己做的水平*.IPC :: RunIPC :: Run3甚至更高.



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

  • 它起作用是因为 `open *STDIN, '&lt;', ...` 将重用相同的 fd,因为它是 `open` 关闭后最低的未打开 fd。它不适用于 `open local *STDIN, '&lt;', ...` 因为 fd 0 没有关闭。 (3认同)
  • 我只想说"在STDIN中存储文件句柄并不会神奇地将其分配给fd 0".非常好.也许如果`system`为STDIN中的句柄分配给孩子的fd 0会好,但事实并非如此,而且改变它也为时已晚. (2认同)