Perl - в то время как (<>) обработка файлов

Простая программа с while( <> ) обрабатывает файлы, указанные в качестве аргументов (./program 1.file 2.file 3.file) и стандартный ввод Unix-систем.

Я думаю, что он объединяет их вместе в один файл и работает по строкам. Проблема в том, как я знаю, что я работаю с первым файлом? А затем со вторым.

Для простого примера я хочу напечатать содержимое файла в одной строке.

while( <> ){
    print "\n" if (it the second file already);
    print $_;
}

Ответы

Ответ 1

Оператор алмаза не объединяет файлы, он просто открывается и читает их последовательно. Как вы контролируете это, зависит от того, как вам это нужно. Простой способ проверить, когда мы прочитали последнюю строку файла, это использовать eof:

while (<>) {
    chomp;             # remove newline
    print;             # print the line
    print "\n" if eof; # at end of file, print a newline
}

Вы также можете рассмотреть счетчик, чтобы отслеживать, какой файл обрабатывается

$counter++ if eof;

Обратите внимание, что этот счет будет увеличиваться на один в последней строке файла, поэтому не используйте его преждевременно.

Если вы хотите отслеживать номер строки $. в текущем дескрипторе файла, вы можете close описать файл ARGV на reset этот счетчик:

while (<>) {
    print "line $. : ", $_;
    close ARGV if eof;
}

Ответ 2

<> - частный случай оператора readline. Обычно он принимает дескриптор файла: <$fh>.

Если дескриптор файла не используется, тогда используется мануал файла ARGV.

Если аргументы командной строки не заданы, то ARGV - STDIN. Если заданы аргументы командной строки, то ARGV будет open ed для каждого из них по очереди. Это похоже на

# Pseudocode
while ($ARGV = shift @ARGV) {
  open ARGV, $ARGV or do{
    warn "Can't open $ARGV: $!";
    next;
  };
  while (<ARGV>) {
    ...; # your code
  }
}

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

Помните, что форма с двумя аргументами open (которая, вероятно, используется здесь за кулисами), является довольно небезопасной. Имя файла rm -rf * | может не делать то, что вы хотите.

Ответ 3

Имя текущего файла для <> содержится в специальной переменной $ARGV .

Вы можете перекрестно сопоставить свой список файлов из массива параметров @ARGV с текущим именем файла, чтобы получить позицию файла в списке. Предполагая, что единственными параметрами, которые вы ожидаете, являются имена файлов, вы можете просто сделать:

my %filename_positions = map { ( $ARGV[$_] => $_ ) } 0..$#ARGV;

while (<>) {
    my $file_number = $filename_positions{$ARGV};
    #... if ($file_number == 0) { #first file     
}