首页 > 解决方案 > 正则表达式比较部分文件名然后移动到另一个目录 perl

问题描述

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

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

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

在目录内:

13209811124300209156562070_cake_872_trucks.rts

在命令内:

{"file 872","cake_872_trucks.rts",running}

@events数组中:

cake_872_卡车

我的代码:

#!/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 

标签: fileperlfilesystemsmove

解决方案


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

我认为过长(且不完整)的正则表达式可以达到预期的目的。

我不确定要移动的文件与 中的原始文件有何关系@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]
}

正则表达式仅匹配(为什么@allfiless///? 更改名称),并捕获。

第一组括号将那个长的前导因子(数字)捕获到 中,第二组括号$1将名称 ( cake_872_trucks)捕获到 中,第三组括号$2具有扩展名 in $3

因此,您最终会得到一个带有感兴趣名称的键的哈希,它们的值是带有文件名的所有其他需要组件的数组引用。请根据需要进行调整,因为我不知道该正则表达式的作用并且可能遗漏了某些部分。

现在,一旦您完成,@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完成(并注意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运算符在其中构建正则表达式模式。

根据您的实际需要调整那些捕获括号、锚点等。将其分解以便将正则表达式明智地拆分为变量将对可读性和正确性大有帮助。

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


推荐阅读