【问题标题】:How can I change the standard output filehandle for a system call in Perl?如何在 Perl 中更改系统调用的标准输出文件句柄?
【发布时间】:2009-06-13 15:53:06
【问题描述】:

我正在尝试使用 select 更改系统函数的标准输出。但它似乎不起作用。系统输出显示在控制台上,而不是重定向到文件。

use strict;
use warnings;

chdir "C:\\Documents and Settings\\" or die "cannot open the dir\n";
open FH, ">out.txt" or die "cannot open out.txt\n";
select FH or die " cannot change the stdout\n";
system "dir /a" ; 

虽然我可以system "dir /a > out.txt",但我想知道为什么上面的代码不起作用。

【问题讨论】:

    标签: perl qx


    【解决方案1】:

    select 函数更改输出的默认文件句柄。它不会更改 STDOUT,无论它是否是输出的默认文件句柄,它都指向它所指向的任何内容。如果要更改 STDOUT,则必须执行 ylebre 或 Jon's answer 之类的操作。

    当您启动子进程时,它会获得与父进程相同的标准输出。它并不关心父级的默认文件句柄是什么。

    【讨论】:

      【解决方案2】:

      您的代码的问题是system 命令没有为您捕获输出。你可以使用qx//:

      use strict;
      use warnings;
      
      open my $fh, ">", "output.txt" or die $!;
      my $oldfh= select $fh;
      print qx/ls -a/;
      select $oldfh;
      close $fh or warn $!;
      

      还有其他选项可以运行外部应用程序并读取它的输出,例如 IPC::Open2IPC::Open3 模块。它们默认包含在 perl 中。

      附注:不要使用 glob 作为文件句柄:它们是全局变量,而全局变量是邪恶的。改用词法变量(FH vs. $fh)。另外,您应该使用三个参数open 而不是两个参数,因为前者比后者更安全。

      【讨论】:

      • Igor,我的论点是 dir 命令应该获得与调用它的 perl 程序相同的标准输出。既然我们用文件欺骗了标准输出,那么系统的输出不应该转到文件吗?
      • 不,不是。当您运行 system("dir /a") 时,perl 会将您的 shell(在您的情况下为 cmd.exe)作为分叉进程运行,并以“dir /a”作为参数。当你使用 qx// 时,perl 会为你返回这个分叉进程的输出。希望这能澄清一点。
      【解决方案3】:

      也许this 有帮助

      【讨论】:

        【解决方案4】:

        在这种情况下,我不确定“选择”是您要查找的内容。要将 STDOUT 重定向到文件,您可以执行以下操作:

        use strict;
        use warnings;
        use IO::Handle;
        open FH, "> out.txt";
        STDOUT->fdopen( \*FH, 'w' ) or die $!;
        print "Hello world!\n";
        system "dir /a";
        

        希望这会有所帮助!

        【讨论】:

        • @ylebre,不工作。在 fdopen 中将 OUTPUT 更改为 FH。另外,我想知道为什么选择不起作用。
        【解决方案5】:

        我在系统(不是 Perl)级别重新分配文件描述符:

            sub reopen($$$) {
                open $_[0], $_[1]. '&='. fileno($_[2]) or die "failed to reopen: $!";
            }
        
            reopen *STDOUT,  '>', $new_stdout_handle;
        

        现在你 fork 的任何东西都会认为 $new_stdout_handle 是标准输出。

        我粘贴了一个完整的示例:http://gist.github.com/129407

        【讨论】:

        • 如果您要重新打开 STDERR,该死不会很有帮助。最好通过打开“>&STDERR”来保存现有的stderr,以便在重新打开失败时可以恢复它。
        猜你喜欢
        • 2011-03-15
        • 1970-01-01
        • 2011-10-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-09
        • 1970-01-01
        • 2023-03-08
        相关资源
        最近更新 更多