Как я могу сбросить дескриптор файла, получающего стандартный ввод в Perl?

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

  •  19-09-2019
  •  | 
  •  

Вопрос

Когда я выдаю Perl-скрипту некоторый стандартный ввод, например

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

У меня есть скрипт, который содержит ошибку.Он считывает первую строку стандартного ввода, получает что-то из этой первой строки, а затем анализирует только строки со 2 по n стандартного ввода при последующем чтении:

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

...

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

Поэтому я добавил seek инструкция к этому скрипту, чтобы попытаться сбросить дескриптор файла в начало файла:

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);

Добавление этого seek инструкция работает для ввода в файл, но не для стандартного ввода.Скрипт завершает работу с ошибкой:

 error: could not reset file handle 

Как я могу правильно прочитать первую строку стандартного ввода в начале скрипта, сбросить дескриптор файла, а затем прочитать все строки с 1 по n стандартного ввода?

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

Это было полезно?

Решение

Есть простой способ:

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

//do stuff with first line

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

Другие советы

Редактировать: Недостатком моего первого подхода является то, что он должен загружать все строки из FH в память перед обработкой списка.При таком подходе, использующем функцию open to scalar reference (доступную с версии 5.8.0), такой проблемы не возникнет:

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

...

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

Как насчет:

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

Я не думаю, что вы можете сбросить (или искать (0)) для STDIN.Это не обычный дескриптор файла в виде STDIN.Поскольку на самом деле это не файл, вам потребуется, чтобы STDIN выполнял буферизацию с возможностью сброса.

Я думаю, вам нужно будет специально обработать чтение и повторное использование строки 1.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top