Как закрыть и снова открыть STDOUT в Perl? - PullRequest
10 голосов
/ 21 июня 2011

Я хотел бы закрыть STDOUT, чтобы предотвратить вывод моим кодом определенного изображения, которое мне нужно для дальнейших вычислений, но не требуется на моей веб-странице.

Поэтому я хочу закрыть STDOUT, делайте то, что ясвязано с моим кодом, а затем снова откройте STDOUT для вывода материала на веб-страницу. (не в файл)

То, что я пробовал, это:

    close STDOUT;
    # my code here
    open STDOUT;

Это не работает ...

Спасибо

Ответы [ 6 ]

11 голосов
/ 21 июня 2011

Существует несколько способов решения вашей проблемы, и многие из них не требуют, чтобы вы закрывали STDOUT и рисковали использовать стандартные каналы ввода-вывода вашей программы.

Например, вы можете использовать команду (1-arg) select для направления вывода команд print куда-то временно.

 print $stuff_you_want_to_send_to_STDOUT;

 select(NOT_STDOUT);
 # now default print sends things to NOT_STDOUT.
 # This doesn't need to be a real filehandle, though you may get warning
 # messages if it is not.
 ...;
 print $the_image_you_dont_want_to_go_to_STDOUT;
 ...;

 select(STDOUT);
 # now  print  sends things to STDOUT agin
 print $more_stuff_you_do_want_to_go_to_STDOUT;

Вы также можете переназначить глобус *STDOUT во время выполнения, не закрывая никаких ручек.

 *OLD_STDOUT = *STDOUT;
 print $for_STDOUT;

 *STDOUT = *NOT_STDOUT;     # again, doesn't need to be a real filehandle
 print $stuff_to_suppress;

 *STDOUT = *OLD_STDOUT;     # restore original STDOUT
 print $more_stuff_for_STDOUT;
6 голосов
/ 21 июня 2011

Плохо закрывать STDOUT, так как многое предполагает, что он всегда открыт.Лучше перенаправить его на /dev/null (unix) или nul (Windows).

Если вы хотите перенаправить дескриптор файла,

use Sub::ScopeFinalizer qw( scope_finalizer );

{
    open(my $backup_fh, '>&', \*STDOUT) or die $!;
    my $guard = scope_finalizer { open(STDOUT, '>&', $backup_fh) or die $!; };
    open(STDOUT, '>', '/dev/null') or die $!;

    ...
}

Если вы просто хотите перенаправитьSTDOUT,

{
    local *STDOUT;
    open(STDOUT, '>', '/dev/null') or die $!;

    ...
}

Если вы просто хотите перенаправить дескриптор вывода по умолчанию,

use Sub::ScopeFinalizer qw( scope_finalizer );

{
    open(my $null_fh, '>', '/dev/null') or die $!;
    my $backup_fh = select($null_fh);
    my $guard = scope_finalizer { select($backup_fh); };

    ...
}
3 голосов
/ 21 января 2013

Вы можете реализовать что-то, чтобы поймать STDOUT, вот так:

sub stdout_of (&) {
    my $code = shift;

    local *STDOUT;
    open STDOUT, '>', \(my $stdout_string = '')
        or die "reopen STDOUT: $!";

    $code->();

    return $stdout_string;
}

А затем используйте его так:

my $stdout = stdout_of { print "hello world" };

Локализация дескриптора файла внутри stdout_of () позволяет вам избежать хитростей закрытия и повторного открытия STDOUT.

2 голосов
/ 21 июня 2011

Прочтите документацию для открытия .

Поиск «Вот скрипт, который сохраняет, перенаправляет и восстанавливает STDOUT и STDERR, используя различные методы».

То, что вы хотите сделать, это не закрывать STDOUT, а временно перенаправить его в / dev / null.

1 голос
/ 13 января 2012

Я проверил 2 способа:

  1. через select
  2. через *OLD_STDOUT = * STDOUT, и убедитесь, что они не могут использоваться в общем случае.

Причина в том, что эти 2 подхода перенаправляют STDOUT, только если в Perl Script используется «print» или что-то еще. Но если вы используете вызов system () или индекс вызова, их вывод в любом случае попадет в стандартный STDOUT = ((.

Моя точка зрения, действительно решение должно быть:

#!/usr/bin/perl -w
my $file1 = "/tmp/out.txt";
my $file2 = "/tmp/err.txt";
open my $oldSTDOUT, ">&STDOUT";
open OLDERR, ">&",\*STDERR; 
open(STDOUT, ">$file1")  or print("Can't redirect stdout: to $file1 ");
open(STDERR, ">$file2")  or print("Can't redirect stderr: to $file2 ");
print "THIS OUTPUT ISN'T GOT TO STANDARD OUTPUT\n";
system("pwd"); # this output isn;t got to standard output too, that is right!
close(STDOUT);
close(STDERR);
open STDOUT, ">>&", $oldSTDOUT;
open STDERR, ">>&OLDERR"; 
print "BUT THIS OUTPUT IS SEEN IN A STANDARD OUTPUT\n";

Я проверил это решение, и оно сработало для меня.

1 голос
/ 21 июня 2011

Чтобы (повторно) открыть STDOUT или STDERR как файл в памяти, сначала закройте его:

 close STDOUT;
    open STDOUT, '>', \$variable or die "Can't open STDOUT: $!";

Из документа perl: http://perldoc.perl.org/functions/open.html У вас есть: после закрытияне делай этогоОткрытое выше также должно работать с jus

open STDOUT;

Эта тема в монахах Perl может вам тоже помочь: http://www.perlmonks.org/?node_id=635010

...