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

#!/usr/bin/perl
use File::Basename;

@files = <top8000/rands/*> ; 
$file = 0;
$count = 1; 
while ( open (FILE, $files[$file]) )
{
    while (  $FILEREAD = <FILE> ) 
    {
        if ( $FILEREAD =~ "pattern" ) 
        {
            $count++;        
        };
    };
    $string ="$files[$file]";
    $filename = fileparse($string);
    if ($count >=2 ) {
        rename ( $files[$file] , "top8000/randsort/$filename.txt" );
    };
    $count = 1;
    $file++;
};

Я знаю, что здесь я должен использовать my перед переменными $string и $filename, но моя программа не работает с ним, и я действительно не понимаю, что он делает. Кроме того, я не могу понять, что не так с моей программой. Был бы признателен за любую помощь.

0
user2474041 11 Июн 2013 в 14:15
Есть ли у вас опечатки file и count (переменные без знака доллара перед $file) или это просто проблема копирования / вставки?
 – 
TLP
11 Июн 2013 в 14:20
Когда вы говорите «без изменения имени файла», вы на самом деле имели в виду «и изменение имени файла, добавив расширение '.txt'»? В этом случае это важное отличие.
 – 
TLP
11 Июн 2013 в 14:23
Ох ... исправил ... по-прежнему ничего. Исходным файлом в данном случае является файл .txt. Я имел в виду вообще без изменения имени файла.
 – 
user2474041
11 Июн 2013 в 14:32
Добавьте or die "Cannot rename: $!" в конец вашего оператора переименования. Похоже, вы пытаетесь переместить файл, который все еще открыт для чтения.
 – 
TLP
11 Июн 2013 в 14:36
1
Вы знаете, что не вежливо идти на обеденный перерыв, когда кто-то пытается вам помочь.
 – 
TLP
11 Июн 2013 в 15:11

1 ответ

Лучший ответ

Что ж, похоже, вы сами себе все усложняете. Я предполагаю, что ваша проблема сейчас в том, что вы пытаетесь переименовать файл, который все еще открыт для чтения. Как правило, вы всегда должны проверять возвращаемое значение всех взаимодействий с файлами, например:

open my $fh, "<", $file or die "Cannot open file: $!";
rename $old, $new or die "Cannot rename: $!";

Потому что, вообще говоря, такие ошибки часто следует считать фатальными.

Вашу программу можно значительно упростить, используя некоторые встроенные функции:

use strict;
use warnings;  # always use these two
use File::Copy qw(move);

@ARGV = <top8000/rands/*.txt> unless @ARGV;  # default args    
my $outdir = "top8000/randsort";

while (<>) {           # read through the files
    if (/pattern/) {   # check each line
        close ARGV;    # close the file handle
        move $ARGV, $outdir or die "Cannot move $ARGV: $!";
    }
}

Как видите, вам не нужно указывать имя файла при использовании модуля File::Copy: если адрес назначения - это папка, используется старое имя.

Мы используем ромбовидный оператор <>, который при использовании использует либо стандартный входной дескриптор файла STDIN, либо - в нашем случае - открывает и читает файлы, указанные в качестве аргументов сценария в @ARGV. А поскольку это Perl, мы можем делать все, что захотим, и просто вставлять аргументы по умолчанию, если их нет.

Поскольку ваш счетчик проверил 1 или несколько совпадений, это фактически то же самое, что просто переместить файл при первом совпадении, так почему бы этого не сделать? Просто убедитесь, что вы сначала закрыли файл! Дескриптор файла в этом случае - ARGV. При этом также выполняется переход к следующему файлу в @ARGV, что для нас очень удобно. Имя файла содержится в $ARGV, и нам не нужно больше манипулировать им, поэтому нам больше не нужен модуль File::Basename.

File::Copy - это основной модуль Perl 5, поэтому установка не требуется.

1
TLP 11 Июн 2013 в 14:52