将 STDERR 重定向到 select()ed STDOUT

Redirecting STDERR to select()ed STDOUT

提问人:DevSolar 提问时间:8/29/2023 最后编辑:DevSolar 更新时间:8/29/2023 访问量:97

问:

如何将 STDERR 重定向到与我将 STDOUT 编辑到的进程文件句柄相同的进程文件句柄?[1]select()

  1. 这成功地将 STDERR 重定向到 STDOUT(两行都打印到 STDOUT):

    #!/usr/bin/perl
    
    open( STDERR, '>&', STDOUT );
    
    print "Output to STDOUT\n";
    print STDERR "Output to STDERR (redirected to STDOUT)\n";
    
  2. 这成功地将 STDOUT 通过管道传递到寻呼机(在本例中),而 STDERR 仍直接写入终端。(首先看到 STDOUT,分页,退出寻呼机后,您会看到 STDERR 行。less

    #!/usr/bin/perl
    
    open( my $pager, '|-', 'less' );
    select( $pager );
    
    print "Output to STDOUT (redirected to 'less')\n";
    print STDERR "Output to STDERR\n";
    

我想将两者结合起来 - 将 STDERR 通过管道连接到与 STDOUT 相同的寻呼机。

  1. 这是行不通的,我得到的结果与 2 中的结果相同)。(有趣的是,如果我再次将脚本输出通过管道传输给 - 如 中 - 输出将在 STDOUT 上组合。但是 STDERR 不会通过脚本本身打开的寻呼机进程。less./testme.pl | less

    #!/usr/bin/perl
    
    open( my $pager, '|-', 'less' );
    select( $pager );
    
    open( STDERR, '>&', STDOUT );
    
    print "Output to STDOUT\n";
    print STDERR "Output to STDERR (gets redirected to STDOUT but not to 'less')\n";
    
  2. 这不起作用,STDERR 输出完全消失:

    #!/usr/bin/perl
    
    open( my $pager, '|-', 'less' );
    select( $pager );
    
    open( STDERR, '>', $pager );
    
    print "Output to STDOUT\n";
    print STDERR "Output to STDERR (but does not show up anywhere)\n";
    

如何将 STDERR 重定向到与我将 STDOUT 编辑到的进程文件句柄相同的进程文件句柄?[1]select()


[1]:在实际程序中,我正在检查调用方是否尚未重定向 STDOUT / STDERR。为了简洁起见,我把这些检查排除在示例之外。

这里应该有问题,我很乐意实现相同的效果 - STDOUT 和 STDERR 通过管道传输到同一个寻呼机进程 - 没有 .select()select()

目标平台包括适用于 Windows 的 Git Bash,这严重限制了其他模块的可用性。一个理想的答案可以在没有 ing 的情况下工作,例如。useIPC::Open

perl io-重定向

评论

0赞 Håkon Hægland 8/29/2023
另请参阅 stackoverflow.com/q/3822787/2173773
0赞 ikegami 8/29/2023
关闭。open( STDERR, '>&', $pager );
0赞 DevSolar 8/29/2023
@ikegami:不,这也行不通 - STDERR行根本没有打印,无论是寻呼机进程还是直接终端。
0赞 ikegami 8/29/2023
它确实有效。请注意,使用 而不是 。>&>

答:

3赞 Håkon Hægland 8/29/2023 #1

如何将 STDERR 重定向到与我选择()的 STDOUT 相同的进程文件句柄?

以下内容对我有用:

use v5.38;
my $pid = open( my $pager, '|-', 'less' ) or die "Can't start less: $!";
{
    local *STDOUT = $pager;
    local *STDERR = $pager;
    #select( $pager );

    print "Output to STDOUT\n";
    print STDERR "Output to STDERR\n";
}
close $pager;

对代码的注释

  • 案例#3:这会将STDOUT复制到STDERR中,因此它可以工作,但由于某种原因,它不能与STDER一起使用open( STDERR, '>&', STDOUT );select

  • 案例 #4:这将在写入模式下打开,以显示 给出的文件名。因此,这不会重复任何描述符open( STDOUT, '>', $pager );STDOUT$pager

评论

0赞 DevSolar 8/29/2023
对不起,有几个 (s/STDOUT/STDERR/) 错别字在那里。在问题中修复了它们。(#1 / #4)
0赞 DevSolar 8/29/2023
对我来说效果很好。有什么特别的原因吗?我的脚本是向上工作的,你的构造似乎也适用于那个版本......use v5.38;v5.20
0赞 ikegami 8/29/2023
回复“由于某种原因,它不能与选择一起使用”,原因不会改变。(它更改了 print/printf/say 的默认句柄。您需要相当于selectSTDOUT'>&', select()'>&', $pager
0赞 ikegami 8/29/2023
@DevSolar,回复“使用v5.38的任何特殊原因?”,此代码只需要5.6。 提供,不过。use v5.38;use strict; use warnings;