简体   繁体   English

STDOUT重定向到变量不捕获管道输出

[英]STDOUT redirected to variable not catching pipe output

I want to temporarily redirect stdout to an in memory variable. 我想暂时将stdout重定向到内存变量。 Prints are correctly redirected to my variable but not the output of a pipe (bc in my example). 打印正确地重定向到我的变量但不是管道的输出(在我的示例中为bc)。 What is going on? 到底是怎么回事?

#!/usr/bin/perl

my $stdout_sink;
open(my $orig_stdout, ">&STDOUT") || die $!;
close STDOUT;
open(STDOUT, ">", \$stdout_sink) || die $!;

# produce some output in different ways
print "before bc\n"; # ok
open my $fh, "| bc";
print $fh "2+2\n";   # not ok
close $fh;

close STDOUT;  
open(STDOUT, ">&", $orig_stdout) || die $!;
print "$stdout_sink";

Actual ouput will be: 实际输出将是:

before bc

Expected output: 预期产量:

before bc
4

You have a detailed explanation in mob's answer of why you cannot redirect a child's STDOUT to a variable, which isn't really a filehandle. 你在mob的答案中有一个详细的解释,为什么你不能将孩子的STDOUT重定向到一个变量,这实际上不是一个文件句柄。

Instead, you can use a module for running external programs, that can redirect standard streams to variables. 相反,您可以使用模块运行外部程序,这可以将标准流重定向到变量。 Then you can combine strings with redirected output as you wish. 然后,您可以根据需要将字符串与重定向输出组合在一起。

An example with IPC::Run3 IPC :: Run3的一个例子

use warnings;
use strict;
use feature 'say';

use IPC::Run3;

open my $fh, ">", \my $so_1;     
my $old = select $fh;         # make $fh the default for output,
say "To select-ed default";   # so prints end up in $so_1

run3 ["ls", "-l", "./"], undef, \my $so_2;   # output goes to $so_2

select $old;                  # restore STDOUT as default for output
print $so_1, $so_2;

Here I used select to manipulate where prints go by default (without a filehandle specified). 在这里,我使用select来操作默认打印的位置(没有指定文件句柄)。

Note that the example redirects run3 to a different variable ( $so_2 ) than the one used for a previous redirect. 请注意,例如重定向run3在不同的变量( $so_2 ),比使用以前的重定向的一个。 If you'd rather append to the same variable specify this in %options 如果您更愿意附加到同一个变量,请在%options指定

run3 ["ls", "-l", "./"], undef, \$so_1, { append_stdout => 1 };

and remove $so_2 from the printing statement. 并从打印语句中删除$so_2

The module uses temporary files for this redirection, as mob also indicated in the answer. 该模块使用临时文件进行此重定向,正如回答中也指出的那样。

Some other options are Capture::Tiny that can redirect output from nearly any code, with a simple and clean interface, and the very powerfull, rounded, and more complex IPC::Run . 其他一些选项是Capture :: Tiny ,可以从几乎任何代码重定向输出,具有简单而干净的界面,以及非常强大,圆润,更复杂的IPC :: Run

This is ... not possible. 这是不可能的。

Standard output of piped opens and system calls are written to file descriptor 1. Normally, Perl's STDOUT file handle is associated with file descriptor 1, but that can be manipulated. 管道打开和system调用的标准输出被写入文件描述符1.通常,Perl的STDOUT文件句柄与文件描述符1相关联,但可以对其进行操作。

In this example, the system calls writes to STDOUT filehandle, which writes to the file foo . 在此示例中, system调用写入STDOUT文件句柄,写入文件foo

close STDOUT;             # closes file descriptor 1
open STDOUT, '>', 'foo';  # reopens STDOUT as file descriptor 1
system("echo bar");
close STDOUT;
print STDERR "foo: ",`cat foo`;
# result:  "foo: bar"

But in this example, the system calls writes to the BAZ filehandle. 但在此示例中, system调用写入BAZ文件句柄。

close STDOUT;             # closes file descriptor 1
open BAZ, '>', 'baz';     # attaches fd 1 to handle BAZ
open STDOUT, '>', 'foo';  # opens new file descriptor, maybe fd 3
system("echo bar");
close STDOUT;
print STDERR "foo: ",`cat foo`;
print STDERR "baz: ",`cat baz`;
# result:  "foo: baz: bar"

An in-memory filehandle is not a real filehandle. 内存中的文件句柄不是真正的文件句柄。 If you call fileno on it, you will (generally, may be OS dependent) get a negative number. 如果您在其上调用fileno ,您将(通常可能依赖于操作系统)获得负数。

open STDOUT, '>', \$scalar;
print STDERR fileno(STDOUT);     #   -1

Piped opens and system calls will not be able to write to this filehandle. 管道打开并且系统调用将无法写入此文件句柄。

You will need a more complicated workaround, like writing the piped open output to a file, and then copying that file into the in-memory variable. 您将需要更复杂的解决方法,例如将管道打开输出写入文件,然后将该文件复制到内存中变量中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM