Как перенаправить 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
, Я хочу, чтобы вывод этого вызова тоже был записан.
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
не знает, как сотрудничать.
Есть несколько способов перенаправить и восстановить 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";
Наслаждаться.
Причина, по которой это происходит, заключается в том, что "файловые дескрипторы" STDOUT и STDERR не эквивалентны дескрипторам stderr и stdout, предоставляемым оболочкой для двоичного файла perl. Для достижения того, что вы хотите, вы должны использовать открытый вместо system
Ответ TLDR
Объединенные STDOUT и STDERR
Если ты хочешь
STDOUT
(из
print()
песок
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.