Восстановление указанной строки c в нескольких .txt в каталоге с использованием perl - PullRequest
0 голосов
/ 22 апреля 2020

У меня есть результаты программы, которая дает мне результаты некоторого поиска, давая мне более 2000 файлов TXT архивов. Мне просто нужна указанная строка c в каждом файле, это то, что я пробовал с Perl:

opendir(DIR, $dirname) or die "Could not open $dirname\n";

while ($filename = readdir(DIR)) {
 print "$filename\n";
 open ($filename, '<', $filename)or die("Could not open  file.");
  my $line;
  while( <$filename> ) {
    if( $. == $27 ) { 
    print "$line\n";
    last;
    }
 }
}
closedir(DIR);

Но есть проблема с $ filename в строке 5, и я не Я не знаю альтернативы, поэтому мне не нужно вручную называть каждый файл.

Заранее спасибо.

1 Ответ

1 голос
/ 23 апреля 2020

Несколько проблем с этим кодом:

  • Использование идентификатора без слов старой школы для дескриптора каталога вместо переменной с автовыводом, как вы для дескриптора файла.

  • Использование одной и той же переменной для имени файла и дескриптора файла довольно странно.

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

  • $27?

  • Вы никогда ничего не назначаете этой переменной $line перед печатью it.

  • Если $directory не является текущим рабочим каталогом вашей программы, вы столкнулись с проблемой, упомянутой в readdir документации

    Если вы планируете подавать возвращаемые значения из readdir, вам лучше добавить соответствующий каталог. В противном случае, поскольку мы не сделали chdir там, он бы проверял неверный файл.

    (Заменить открытым для проверки файла)

  • Всегда use strict; и use warnings;.


Лично, если вы просто хотите напечатать 27-ю строку большого количества файлов, я бы обратился к awk и find (с помощью теста -exec, чтобы избежать потенциальных ошибок, связанных с максимальной длиной командной строки):

find directory/ -maxdepth 1 -type -f -exec awk 'FNR == 27 { print FILENAME; print }' \{\} \+

Если вы используете систему Windows без стандарта unix инструменты, подобные установленным, или это часть более крупной программы, исправленный perl путь:

#!/usr/bin/env perl
use strict;
use warnings;
use autodie;
use feature qw/say/;
use File::Spec;

my $directory = shift;
opendir(my $dh, $directory);
while (my $filename = readdir $dh) {
    my $fullname = File::Spec->catfile($directory, $filename); # Construct a full path to the file
    next unless -f $fullname; # Only look at regular files
    open my $fh, "<", $fullname;
    while (my $line = <$fh>) {
        if ($. == 27) {
            say $fullname;
            print $line;
            last;
        }
    }
    close $fh;
}
closedir $dh;

Вы также можете рассмотреть возможность использования glob для получения имен файлов вместо из opendir / readdir / closedir.

И если у вас есть Path :: Tiny , более простая версия:

#!/usr/bin/env perl
use strict;
use warnings;
use autodie;
use feature qw/say/;
use Path::Tiny;

my $directory = shift;
my $dir = path $directory;
for my $file ($dir->children) {
    next unless -f $file;
    my @lines = $file->lines({count => 27});
    if (@lines == 27) {
        say $file;
        print $lines[-1];
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...