正则表达式比较部分文件名然后移动到另一个目录 perl

Regexp to Compare partial filenames then moving to another directory perl

我正在编写一个脚本,用于将目录中的非 运行 文件与来自命令的 运行 文件进行比较。我必须使用正则表达式从目录中删除文件名的前半部分,然后使用正则表达式从命令中删除文件名,然后将不匹配的名称记录到数组中。

我无法弄清楚的部分是如何将文件名从旧目录移动到新目录以供将来删除。

为了移动文件,我需要用通配符将它们括起来,* 由于文件名和扩展名前面的随机数。 前后示例文件名:

在目录内:

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{} = [];
    }
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 

我猜你需要这样的东西:

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;

一旦您使用正则表达式解析文件名,就没有理由不能够捕获所有部分,以便您稍后可以重建文件名的所需部分。

我假设那个过长(且不完整)的正则表达式达到了它的目的。

我不确定要移动的文件与 @allfiles 中的原始文件有何关系,因为这些文件是从 /var/user/data 中获取的,而您的移动尝试使用 /home/user/RunBackup。所以下面的代码片段更通用。

如果移动的恰好是来自 @allfiles 的文件,那么只需保留文件名

my %files;

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

其中 /...(...).../ 我的意思是表明您使用了正则表达式,但是您在匹配名称本身的模式部分周围添加了括号。

然后您可以稍后从感兴趣的 "name" (cake_872_trucks) 中检索文件名。

但是,如果可能需要文件名组件来修补不同的(虽然相关)文件名,则捕获并存储各个组件

my %files;

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

正则表达式仅匹配(为什么要将 @allfiles 中的名称更改为 s///?),并捕获。

第一组括号将那个长引导因子(数字)捕获到 </code>,第二组将名称(<code>cake_872_trucks)捕获到 </code>,第三组有扩展名,在 <code>.

所以你最终得到一个散列,其中的键是感兴趣的名称,它们的值是 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: $!";
    }

我使用的是核心模块File::Copy,而不是去系统中获取移动命令。

可以 也可以通过再次浏览目录来重建名称,现在手头有感兴趣的名称。但这会非常昂贵,因为您必须尝试为目录中读取的每个文件匹配 @events 中的每个名称(O(mn) 复杂性)。

你问的可以用glob (and note 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 operator 构建正则表达式模式。

根据您的实际需要调整捕获括号、锚点等。将其分解以便将正则表达式合理地分成变量将大大提高可读性,从而提高正确性。

假设有充分的理由在文件名中寻找这些特定数字,这也是记录任何此类固定因素的好方法。