2013-05-17 11 views

Odpowiedz

11

Tak, jest. print wysyła swoje wyjście do "wybranego" uchwytu pliku, który zwykle jest STDOUT. Ale Perl udostępnia funkcję select, aby ją zmienić.

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

Funkcja select zwraca poprzednio wybranego uchwytu pliku, dzięki czemu można uchwycić go i przywrócić go później.

my $orig_select = select(STDERR); 
&test; 
select($orig_select); 
+0

+1 Zauważ, że krytyczny wyjątek w teście() pozostawi niestandardowy UCHWYTPLIKU select() d, która jest dlaczego ja local() ize w mojej odpowiedzi poniżej. – pilcrow

9

dynamiczna analiza zakresu Perl poprzez local() nie jest często używany, ale to uderza mnie jako dobrego wniosku o IT:

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

Wezwanie do test() w bloku powyżej - jak do wszystkiego sama usługa może wywoływać - STDOUT będzie dynamicznie dopasowywana do duplikatu STDERR. Kiedy kontrola opuszcza blok, nawet jeśli przez die() ING STDOUT zostaną przywrócone, co było przed blokiem

Uogólnione:

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

test();    # to stdout 
out2err { test() }; # to stderr 
test();    # to stdout 
+1

+1 To zadziała, nawet jeśli dana funkcja zostanie jawnie wypisana do 'STDOUT'. – chepner

3

Tymczasem, można również „capture wydruków podprogramu do zmiennej . "

Wystarczy przejść skalarne ref do 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: >>>$_<<<"; 
} 

wyjściowa:

Captured as string: >>>lalala\nmore stuff\n2 = 2\n1\n2\n3\n<<<