Как я могу unalias из STDOUT Perl? - PullRequest
2 голосов
/ 17 марта 2009

Когда я запускаю это:

open FP, ">xyz";

my $file = *FP;

printf $file "first\n";

$file = *STDOUT;

printf $file "second\n";

open $file, ">abc";

print $file "third\n";

print STDOUT "fourth\n";

print FP "fifth\n";

«Четвертый» отпечаток не идет к STDOUT, а скорее к «abc».

STDOUT отличается от FP, который ведет себя как ожидалось.

Что я делаю не так? Что я не понимаю?

Ответы [ 6 ]

11 голосов
/ 17 марта 2009

Ну, для начала, вы неправильно используете 'open'.

open my $fp , '>', 'xyz' ;

Рекомендуемый синтаксис.

Настоятельно рекомендуется использовать оголенное «FP», поскольку оно не является лексическим.

Во-вторых, вы открываете файловые указатели как новые вещи. Это не очень хорошая практика, это не должно быть проблемой, но это просто плохая идея. Вы должны закрыть указатель файла или позволить ему выйти из области видимости (через лексический).

В-третьих, «* STDOUT» является ссылкой.

my $fh = *STDOUT; 
print "$fh\n";   #prints  '*main::STDOUT';

Итак, когда вы делаете это:

open $fh, '>abc'; 

вы делаете

open *STDOUT, '>abc'; 

и если вы сразу после этого сделаете

print "$fh\n"; 

вы заметите, что он все еще печатает *main::STDOUT;

Некоторые интересные фрагменты кода, которые проясняют это:

my $fh = *STDOUT;
open $fh, '<', "foo.txt"; 
print $fh "hello";
# Filehandle STDOUT opened only for input at (eval 288) line 6.

my $fh = *STDIN;
open $fh, '<', "foo.txt"; 
print <>; 
# contents of foo.txt here 

Вот рекомендуемый способ использования open:

sub foo { 
    my $fh;
    open $fh , '<', 'file.txt' or Carp::croak('Cannot Open File.txt'); 
    # do stuff with $fh; 
    close $fh or Carp::carp('Something annoying in close :S '); 
}

Обратите внимание, что если вы опустите close, файл закроется, как только $ fh выйдет из видимости.

6 голосов
/ 17 марта 2009

Если я понимаю, что вы пытаетесь сделать, я думаю, вы хотите использовать select. Это позволяет легко переключаться между файловыми дескрипторами. Вам также следует использовать более современную форму open (3 аргумента, лексические файловые дескрипторы и проверку ошибок). См. perldoc perlopentut.

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

open my $fh,  '>', 'abc' or die "Can't open 'abc': $!";
open my $fh2, '>', 'def' or die "Can't open 'def': $!";
open my $fh3, '>', 'xyz' or die "Can't open 'xyz': $!";

select $fh;
print "First\n";

# Later
select $fh2;
print "Second\n";

# Later
select $fh3;
print "Third\n";

# Later
select STDOUT;
print "Fourth\n";
4 голосов
/ 17 марта 2009

Вам нужно сохранить STDOUT, чтобы вы могли восстановить его. Это из ... perldoc для open :

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

#!/usr/bin/perl
open my $oldout, ">&STDOUT"     or die "Can't dup STDOUT: $!";
open OLDERR,     ">&", \*STDERR or die "Can't dup STDERR: $!";

open STDOUT, '>', "foo.out" or die "Can't redirect STDOUT: $!";
open STDERR, ">&STDOUT"     or die "Can't dup STDOUT: $!";

select STDERR; $| = 1;  # make unbuffered
select STDOUT; $| = 1;  # make unbuffered

print STDOUT "stdout 1\n";  # this works for
print STDERR "stderr 1\n";  # subprocesses too

open STDOUT, ">&", $oldout or die "Can't dup \$oldout: $!";
open STDERR, ">&OLDERR"    or die "Can't dup OLDERR: $!";

print STDOUT "stdout 2\n";
print STDERR "stderr 2\n";

Посмотрите на части "или умри". Вы всегда должны проверять наличие ошибок ...

3 голосов
/ 18 марта 2009

Локализация STDOUT. Затем вы можете использовать псевдоним в ограниченной динамической области. После того, как вы покинете эту область, STDOUT вернется в нормальное состояние.

use strict;
use warnings;

print_stuff('Normal STDOUT');

{   local *STDOUT;
    open( STDOUT, '>', 'out' ) 
         or die "Can't redirect STDOUT: $!";
    local $| = 1;  # Unbuffer handle. 
                   # Do this AFTER redirecting STDOUT.

    print_stuff('Aliased to out');

    sleep 10;
} 


print_stuff('Back to normal STDOUT');

sub print_stuff {
    print join "\n", @_, '';
}
1 голос
/ 17 марта 2009

Когда вы делаете , открываете файл $, "> abc" , то, над чем вы в основном работаете, - это файловый дескриптор для STDOUT, который вы теперь открыли для другой цели. То есть оба ваших псевдонима работают с одним базовым ресурсом, который перераспределяется, независимо от того, какой псевдоним используется для обращения к нему, когда вы делаете это open .

0 голосов
/ 18 марта 2009

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

{
  open my $fh, '>', 'abc';
  print $fh "assorted data";
  close $fh;
}

В качестве дополнительного преимущества вам даже не нужно иметь строку 'close $fh;', поскольку она будет автоматически закрыта, когда переменная выйдет из области видимости.

Если вы собираетесь использовать эту технику, вы всегда должны локализовать любые глобальные переменные, которые изменяются внутри блока кода.

{
  local *FH;
  open FH, '>', 'abc';
  print FH "assorted data";
  close FH;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...