Regexp для сравнения частичных имен файлов, а затем перейти на другой каталог Perl - PullRequest
0 голосов
/ 22 октября 2018

Я работаю над сценарием, чтобы сравнить неиспользуемые файлы в директории с запущенными файлами из команды.Я должен использовать Regex, чтобы удалить переднюю половину имен файлов из dir, а затем regex, чтобы удалить имена файлов из команды, которая затем записывает несопоставленные имена в массив.

Часть, которую я не могу понять, это как я могу переместить имена файлов из старого каталога в новый каталог для последующего удаления.

Чтобы переместить файлы, мне нужно заключить их в*, из-за случайных чисел перед именами файлов и расширением.Примеры имен файлов до и после:

в каталоге:

13209811124300209156562070_cake_872_trucks.rts

в команде:

{"file 872", "cake_872_trucks.rts", работает}

в @events массиве:

cake_872_trucks

Мой код:

#!/usr/bin/perl -w
use strict;
use warnings;
use File::Copy qw(move);
use Data::Dumper;
use List::Util 'max';
my $orig_dir = "/var/user/data/";
my $dest_dir = "/var/user/data/DeleteMe/";
my $dir = "/var/user/data";
opendir(DIR, $dir) or die "Could not open $dir: $!\n";
my @allfiles = readdir DIR;
close DIR;
my %files;
foreach my $allfiles(@allfiles) {
$allfiles =~ m/^(13{2}638752056463{2}635181_|1[0-9]{22}_|1[0-9]{23}_|1[0-9]{24}_|1[0-9]{25}_)([0-9a-z]{4}_8[0-9a-z]{2}_[0-9a-z]{2}[a-z][0-9a-z]0[0-9]\.rts|[a-z][0-9a-z]{3}_[0-9a-z]{4}_8[0-9a-z]{2}_[0-9a-z]{2}[a-z]{2}0[0-9]\.rts|[a-z]{2}[0-9a-z][0-9]\N[0-9a-z]\N[0-9]\N[0-9]\N[0-9a-z]{4}\N[0-9]\.rts|[a-z]{2}[0-9a-z]{2}\N{2}[0-9a-z]{2}\N{2}[0-9][0-9a-z]{2}\N[0-9]{2}\.rts|S0{2}2_86F_JATD_01ZF\.rts)$/im;

$files{$2} = [$1];
    }
my @stripfiles = keys %files;
my $cmd = "*****";
my @runEvents = `$cmd`;
chomp @runEvents;
foreach my $running(@runEvents) {
$running =~ s/^\{"blah 8[0-9a-z]{2}","(?<field2>CBE1_D{3}1_8EC_J6TG0{2}\.rts|[0-9a-z]{4}_8[0-9a-z]{2}_[0-9a-z]{2}[a-z][0-9a-z]0[0-9]\.rts|[a-z]{2}[0-9a-z]{2}\N{2}[0-9a-z]{2}\N{2}[0-9][0-9a-z]{2}\N[0-9]{2}\.rts)(?:",\{239,20,93,5\},310{2},20{3},run{2}ing\}|",\{239,20,93,5\},310{2},[0-9]{2}0{3},run{2}ing\}|",\{239,20,93,5\},310{2},[0-9]{3}0{4},run{2}ing\}|",\{239,20,93,5\},3[0-9]0{2},[0-9]{2}0{4},run{2}ing\})$/$+{field2}/img;

}
my @events = grep {my $x = $_; not grep {$x =~/\Q$_/i}@runEvents}@stripfiles;
foreach my $name (@events) {
my ($randnum, $fnames) = { $files{$name}};
my $combined = $randnum . $fnames;
print "Move $file from $orig_dir to $dest_dir";
move ("$orig_dir/$files{$name}", $dest_dir)
or warn "Can't move $file: $!";
}
#print scalar(grep $_, @stripfiles), "\n";
#returned 1626
#print scalar(grep $_, @runEvents), "\n";
#returned 102  
#print scalar(grep $_, @allfiles), "\n";
#returned 1906 

Ответы [ 2 ]

0 голосов
/ 23 октября 2018

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

Я предполагаю, что это слишком долго (и не полностью)regex делает то, для чего предназначен.

Я не уверен, как перемещаемые файлы относятся к исходным файлам в @allfiles, поскольку они извлекаются из /var/user/data, пока ваша попытка перемещения использует /home/user/RunBackup.Поэтому приведенные ниже фрагменты кода являются более общими.

Если перемещаются именно файлы из @allfiles, тогда просто сохраните имя файла

my %files;

foreach my $oldfile (@allfiles) {
    $oldfile =~ m/...(...).../;    # your regex, but capture the name
    $files{$1} = $oldfile;
}

, где под /...(...).../ я имею в виду, чтобы указатьчто вы используете свое регулярное выражение, но к которому вы добавляете круглые скобки вокруг части шаблона, которая совпадает с самим именем.

Затем вы можете позже извлечь имя файла из "имени", представляющего интерес (cake_872_trucks).

Если, однако, компоненты имени файла могут потребоваться для исправления другого (связанного) имени файла, тогда захватите и сохраните отдельные компоненты

my %files;

foreach my $oldfile (@allfiles) {
    $oldfile =~ m/(...)(...)(...)/;  # your regex, just with capture groups
    $files{$2} = [$1, $3];           # add to %files: name => [number, ext]
}

Регулярное выражение только совпадает (зачем менять имена в@allfiles с s///?) И захватывает.

Первый набор скобок фиксирует этот длинный ведущий фактор (число) в $1, второй получает имя (cake_872_trucks) в $2, а третий имеет расширение в $3.

Таким образом, вы получите хеш с ключами, представляющими интерес, с их значениями в виде arrayrefs со всеми другими необходимыми компонентами имени файла.Пожалуйста, внесите необходимые изменения, так как я не знаю, что делает это регулярное выражение и, возможно, пропустил некоторые части.

Теперь, пройдя @events, вы можете перестроить имя

use File::Copy qw(move);

foreach my $name (@events) {
    my ($num, $ext) = @{ $files{$name} };
    my $file = $num . $name . $ext;
    say "Move $file from $orig_dir to $dest_dir";
    move("$orig_dir/$file", $dest_dir)  or warn "Can't move $file: $!";
}

Ноесли файлы для перемещения действительно из @allfiles (как было бы в этом примере), тогда используйте первую версию выше, чтобы сохранить имена файлов как значения в %files и теперь получить их

foreach my $name (@events) {
    move ("$orig_dir/$files{$name}", $dest_dir) 
        or warn "Can't move $file: $!";
    }

Iиспользуйте модуль ядра File :: Copy вместо того, чтобы выходить в систему с командой на перемещение.

Вы можете также перестроить имя, пройдя через каталогопять же, теперь с именами интересов под рукой.Но это будет очень дорого, так как вы должны пытаться сопоставить каждое имя в @events для каждого файла, считываемого в каталоге ( O (mn) сложность).

То, о чем вы спрашивали, можно выполнить с помощью glob (и обратите внимание, File :: Glob , версия)

my @files = glob "$dir/*${name}*";

но вы 'Я должен был делать это для каждого $name - огромная и ненужная трата ресурсов.


Если это регулярное выражение действительно должно прописывать конкретные числа, вот способ организовать его для облегчения переваривания (и отладки!): Разбить его на разумные части, с отдельной переменной для каждого.

В идеале каждая часть чередования должна представлять собой одну переменную

my $p1 = qr/.../;
my $p2 = qr/.../;
...

my $re_alt = join '|', $p1, $p2, ...;

my $re_other = qr/.../;

$var =~ m/^($re_alt)($re_other)(.*)$/;  # adjust anchors, captures, etc

, где оператор qr создает шаблон регулярного выражения.

Отрегулируйте эти захватывающие скобки,якоря и т. д. для ваших реальных потребностей.Разбив его так, чтобы регулярное выражение было разумно разбито на переменные, будет иметь большое значение для удобочитаемости и, следовательно, правильности.

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

0 голосов
/ 22 октября 2018

Полагаю, вам нужно что-то вроде этого:

my $path = '/home/user/RunBackup/';
my @files = map {$path."*$_*"} @events;
system(join " ", "mv", @files, "/home/user/RunBackup/files/");

Если существует много файлов, вам может понадобиться переместить их один за другим:

system(join " ", "mv", $_, "/home/user/RunBackup/files/") for @files;
...