8

假设我们有:

sub test {
        print "testing\n";
}

如果在某种情况下我想让它打印到 stderr 而不是 stdout,有没有办法可以调用子例程来执行此操作?或者我可以将输出捕获到变量然后使用警告吗?我对 perl 还很陌生。

4

4 回答 4

12

就在这里。print将其输出发送到“选定”文件句柄,通常是STDOUT. 但是 Perl 提供了select更改它的功能。

select(STDERR);
&test;           # send output to STDERR
select(STDOUT);  # restore default output handle

select函数返回先前选择的文件句柄,因此您可以捕获它并在以后恢复它。

my $orig_select = select(STDERR);
&test;
select($orig_select);
于 2013-05-17T18:05:19.190 回答
9

Perl 通过local()的动态作用域并不经常使用,但这让我觉得它是一个很好的应用程序:

test(); # to stdout
{
    open(local *STDOUT, ">&STDERR") or die "dup out to err: $!";
    test(); # to stderr, locally calling it "STDOUT"
}
test(); # to stdout again

上面块中的调用test()——以及任何它test()本身可能调用的东西——将把 STDOUT 动态限定为你的 STDERR 副本。当控制离开块时,即使通过die()ing,STDOUT 也会恢复到块之前的状态

广义:

sub out2err(&) {
  my $user_block = shift;
  open(local *STDOUT, ">&STDERR") or die $!;
  $user_block->();
}

test();             # to stdout
out2err { test() }; # to stderr
test();             # to stdout
于 2013-05-17T18:05:19.573 回答
3

同时,您还可以“将子程序的打印输出捕获到变量中”。

只需将标量 ref 传递给open

#! /usr/bin/env perl
use common::sense;
use autodie;

sub tostring (&) {
  my $s;
  open local *STDOUT, '>', \$s;
  shift->();
  $s
}

sub fake {
  say 'lalala';
  say 'more stuff';
  say 1 + 1, ' = 2';
  say for @_;
}

for (tostring { fake(1, 2, 3) }) {
  s/\n/\\n/g;
  say "Captured as string: >>>$_<<<";
}

输出:

Captured as string: >>>lalala\nmore stuff\n2 = 2\n1\n2\n3\n<<<
于 2013-05-18T02:44:22.317 回答
1

This work for me

local *STDOUT;
open(STDOUT, ">", \$Result);
&test();
print $Result;
于 2019-04-03T15:13:58.207 回答