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

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

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

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

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

person Mantas Marcinkus    schedule 17.02.2013    source источник
comment
выглядит очень похоже на следующую тему SO: является оператором Perl Diamond, который в настоящее время читает из "> stackoverflow.com/questions/13584944/   -  person varnie    schedule 17.02.2013


Ответы (3)


Алмазный оператор не объединяет файлы, он просто открывает и читает их последовательно. То, как вы контролируете это, зависит от того, как вам нужно его контролировать. Простой способ проверить, прочитали ли мы последнюю строку файла, — использовать 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 сбросить этот счетчик:

while (<>) {
    print "line $. : ", $_;
    close ARGV if eof;
}
person TLP    schedule 17.02.2013
comment
Спасибо, ваш ответ очень помог! - person Mantas Marcinkus; 17.02.2013
comment
@MantasMarcinkus Пожалуйста. - person TLP; 17.02.2013
comment
См. perldoc -f eof для получения дополнительной информации об обнаружении границ между файлами, читаемыми оператором <>. - person chepner; 17.02.2013

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

Если дескриптор файла не указан, то используется волшебный дескриптор файла ARGV.

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

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

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

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

person amon    schedule 17.02.2013

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

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

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

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