Как перенаправить STDOUT и STDERR в переменную

Я хочу перенаправить STDERR и STDOUT в переменную. Я сделал это.

close(STDOUT);
close(STDERR);

my $out;
open(STDOUT, ">>", \$out);
open(STDERR, ">>", \$out);

for(1..10)
{
    print "print\n"; # this is ok. 
    warn "warn\n"; # same
    system("make"); # this is lost. neither in screen nor in variable.
}

Проблема с system. Я хочу, чтобы вывод этого вызова также был захвачен.


person Deck    schedule 11.12.2010    source источник


Ответы (6)


Вы пытаетесь зафиксировать вывод в переменной? Если это так, вы использовали обратные кавычки или qx{} с соответствующим перенаправлением. Например, вы можете использовать:

#/usr/bin/env perl
use strict;
use warnings;

# Ensure we have a way to write messages
open my $fh, '>', "output" or die;

close(STDOUT);
close(STDERR);

my $out;
open(STDOUT, ">>", \$out) or do { print $fh, "failed to open STDOUT ($!)\n"; die };
open(STDERR, ">>", \$out) or do { print $fh, "failed to open STDERR ($!)\n"; die };

foreach my $i (1..10)
{
    print "print $i\n"; 
    warn "warn $i\n";
    my $extra = qx{make pth$i 2>&1};
    print $fh "<<$i>><<$out>><<$extra>>\n";
}

(У меня в каталоге случайно оказались программы pth1, pth2 и pth3 - их сделали нормально; pth4 и выше пишут ошибки в stderr; нужно было перенаправление.)

Вы всегда должны проверять успешность таких операций, как open().

Почему это необходимо? Потому что запись в переменную требует сотрудничества процесса, выполняющего запись, а make не знает, как сотрудничать.

person Jonathan Leffler    schedule 11.12.2010

используйте Capture::Tiny!

person salva    schedule 11.12.2010

Существует несколько способов перенаправить и восстановить STDOUT. Некоторые из них также работают со STDERR. Вот два моих фаворита:

Использование select:

my $out;
open my $fh, ">>", \$out;
select $fh;
print "written to the variable\n";
select STDOUT;
print "written to original STDOUT\n";

Использование local:

my $out
do {
    local *STDOUT;
    open STDOUT, ">>", \$out;
    print "written to the variable\n";
};
print "written to original STDOUT\n";

Наслаждаться.

person mndrix    schedule 10.07.2014

Причина, по которой это происходит, заключается в том, что «дескрипторы файлов» STDOUT и STDERR не эквивалентны дескрипторам stderr и stdout, предоставленным оболочкой для двоичного файла Perl. Чтобы достичь того, чего вы хотите, вы должны использовать open вместо system

person grncdr    schedule 11.12.2010
comment
@Israfil: это способ сделать это. - person Jonathan Leffler; 11.12.2010

Почему не use IPC::Open3?

person Dallaylaen    schedule 11.12.2010

Ответ TLDR

use Capture::Tiny;

Объединение STDOUT и STDERR

Если вы хотите, чтобы STDOUT (из print()s) и STDERR (из warn()s) были объединены, используйте...

my ($merged,  @result) = capture_merged { print "Hello, world!" };  # static code
my ($merged,  @result) = capture_merged { eval $codetoeval };       # code in variable

Разделенные STDOUT и STDERR

Если вы хотите, чтобы они разделились...

my ($stdout, $stderr, @result) = capture { print "Hello, world!" };   # static code
my ($stdout, $stderr, @result) = capture { eval $codetoeval };        # code in variable

Результаты оценки

@result указывает на успех, где успех равен [1], а неудача - []. У Tiny есть множество других функций, которые вы можете просмотреть для других случаев, таких как ссылки на код и т. д. Но я думаю, что приведенный выше код должен удовлетворить большинство потребностей любого разработчика Perl.

person HoldOffHunger    schedule 06.07.2021