Como posso redefinir um identificador de arquivo recebendo entrada padrão no Perl?

StackOverflow https://stackoverflow.com/questions/1886103

  •  19-09-2019
  •  | 
  •  

Pergunta

Quando emite um script perl alguma entrada padrão, por exemplo

$ awk '{print $1"\t"$2}' foo.txt | myScript.pl

Eu tenho um script que contém um bug. Ele lê a primeira linha de entrada padrão, obtém algo dessa primeira linha e, em seguida, apenas as linhas 2 a n da entrada padrão na leitura subsequente:

open (FH, "< $input") or die $?;
my $firstLine = <FH>; // reads first line

...

while (my $line = <FH>) {
    // reads lines 2 through n
}
close (FH);

Então eu adicionei um seek Declaração para este script para tentar redefinir o identificador de arquivo para o início do arquivo:

use Fcntl qw(:seek);

...

open (FH, "< $input") or die $?;
my $firstLine = <FH>; // reads first line
seek (FH, 0, SEEK_SET) or die "error: could not reset file handle\n"; // should reset file handle

...

while (my $line = <FH>) {
    // reads lines 1 through n (in theory)
}
close (FH);

Adicionando isso seek A instrução funciona para entrada de arquivo, mas não para entrada padrão. O script trava com o erro:

 error: could not reset file handle 

Como posso ler corretamente a primeira linha de entrada padrão no início do script, redefinir a alça do arquivo e depois ler todas as linhas 1 a n da entrada padrão?

Acho que posso escrever um caso especial para armazenar e processar a primeira linha antes do while Loop, mas espero que haja uma solução mais limpa para esse problema que me permite lidar com a entrada padrão e a entrada do arquivo.

Foi útil?

Solução

Existe uma maneira fácil:

open (FH, "< $input") or die $?;
my $line = <FH>; // reads first line

//do stuff with first line

do {
    //stuff
} while ($line = <FH>);

Outras dicas

EDITAR: Desvantagem da minha primeira abordagem é que ela deve carregar todas as linhas de FH na memória antes de processar a lista. Essa abordagem, usando o recurso de referência aberto ao escalar (disponível desde 5.8.0) não terá esse problema:

my $firstline = <FH>;
open(my $f1, '<', \$firstline);

...

while (my $line = <$f1> || <FH>) {
    # process line 1 through n
}

Que tal:

for my $line ($firstline, <FH>) {
    # process lines 1 through n
}

Eu não acho que você possa redefinir (ou procurar (0)) para stdin. Não é um identificador de arquivo normal como stdin. Como não é realmente um arquivo, você exigiria o buffer resetável do STDIN.

Eu acho que você precisará lidar com a leitura e a reutilização da linha 1, especialmente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top