Perl: Как получить имя файла при использовании <> конструкции?

Perl предлагает эту очень приятную функцию:

while ( <> )
{
    # do something
}

..., который позволяет использовать script как script.pl <filename>, а также cat <filename> | script.pl.

Теперь, есть ли способ определить, был ли вызов script первым, и если да, то какое имя файла было?

Я знаю, что знал это однажды, и знаю, что я даже использовал конструкцию, но я не могу вспомнить, где/как. И было очень сложно искать "сеть для этого" ( "perl stdin filename"? Нет...).

Помогите, пожалуйста?

Ответы

Ответ 1

Переменная $ARGV содержит текущий обрабатываемый файл.

$ echo hello1 > file1
$ echo hello2 > file2
$ echo hello3 > file3
$ perl -e 'while(<>){s/^/$ARGV:/; print;}' file*
file1:hello1
file2:hello2
file3:hello3

Ответ 2

раздел "Операторы ввода/вывода" perlop очень информативен.

По существу, в первый раз <> выполняется, - добавляется к @ARGV, если он запущен пустым. Открытие - приводит к клонированию дескриптора файла STDIN, а переменная $ARGV устанавливается на текущий элемент @ARGV по мере его обработки.

Здесь полный клип.

Нулевой дескриптор файла "< > " является особым: его можно использовать для эмуляции    поведение sed и awk, а также любую другую программу фильтров Unix, которая принимает    список имен файлов, делая то же самое для каждой строки ввода из всех    их. Вход от "< > " поступает либо от стандартного ввода, либо от каждого    файл, указанный в командной строке. Вот как это работает: в первый раз     "< > " оценивается, массив @ARGV проверяется, и если он пуст,    $ ARGV [0] установлен на "-", который при открытии дает вам стандартный ввод.    Затем массив @ARGV обрабатывается как список имен файлов. Цикл

   while (<>) {
       ...                     # code for each line
   }

эквивалентен следующему Perl-подобному псевдокоду:

   unshift(@ARGV, '-') unless @ARGV;
   while ($ARGV = shift) {
       open(ARGV, $ARGV);
       while (<ARGV>) {
           ...         # code for each line
       }
   }

за исключением того, что это не так громоздко говорить, и на самом деле будет работать. Это    действительно сдвигает массив @ARGV и помещает текущее имя файла в    $ ARGV. Он также использует файл ARGV вручную. "< > " - это просто    синоним "<ARGV> ", который является магическим. (Псевдокод выше не    потому что он рассматривает "<ARGV> " как не магический.)

Ответ 3

Если вам интересно узнать, когда <> переключается на новый файл (например, в моем случае - я хотел записать новое имя файла и номер строки), eof() предлагает трюк:

# reset line numbering on each input file
while (<>) {
    next if /^\s*#/;  # skip comments
    print "$.\t$_";
} continue {
    close ARGV if eof;  # Not eof()!
}