用于重命名批量文件的Perl代码

时间:2014-01-01 19:54:32

标签: perl

我在dir中有一些文件,现在我想重命名文件(添加后缀和更改扩展名)。

输入:

XXIN123.timestamp.dat
XXIN123.timestamp.dat
XXIN123.timestamp.dat
XXIN123.timestamp.dat
XXIN123.timestamp.dat

最终输出:

XXX.123_456.newtimestamp.XXIN123.timestamp.csv
XXX.123_456.newtimestamp.XXIN123.timestamp.csv
XXX.123_456.newtimestamp.XXIN123.timestamp.csv
XXX.123_456.newtimestamp.XXIN123.timestamp.csv

首先在dir中搜索特定的模式文件,然后为它们添加后缀。

$oldpat = "XXIN123"
$newpat = "XXX.123_456"

然后将所有.dat个文件重命名为.csv

它不能在第一次运行时运行,但在第二次运行中正常运行并覆盖第一个文件。

CODE:

use File::Copy;
use POSIX;
use strict;

my ( $dir, $oldpat, $newpat, $destdir );
my ( $oldname, $currenttime );
$dir         = '/home/sd1/a1';
$destdir     = '/home/sd1/a1/destination';
$oldpat      = "XXIN123";
$newpat      = "XXX.123_456";
$currenttime = strftime( "%Y%m%d%H%M%S", localtime );
opendir( DH, $dir ) || die "Cannot open $dir: $!";
my @files = readdir DH; 

foreach (@files) {
    $oldname = $_; 
    ## Original find and replace
    s/$oldpat/$newpat.$currenttime.$oldpat/;
    next if ( !-f "$dir/$oldname" );
    if ( !rename "$dir/$oldname", "$destdir/$_" ) { 
        warn "Could not rename $oldname\n";    #$oldname to $_: $!"
    } else {
        print "File $oldname renamed to $_\n";
    }   
    close(DH);

    # renaming
    opendir( DIR, $destdir ) or die "Can't opendir $destdir: $!";
    while ( defined( my $file = readdir DIR ) ) { 

        # ignore current and parent directory . and ..
        next if $file =~ /^\.\.?$/;
        my $new = $file;

        # substitute new file extension
        $new =~ s/\.dat$/\.csv/;
        rename( $file, $new );
        print "File $file renamed to $new\n";
    }   
    close(DIR);
}

2 个答案:

答案 0 :(得分:1)

有一个基于Perl的rename命令 - 它出现在Camel Book的第1版中,但在较旧的SO问题中被引用并且可以在互联网上找到。 (您可能会发现它命名为prename。)

你可以用它来完成这项工作:

rename "s/(.*)\.dat$/XXX.123_456.$(date +'%Y%m%d%H%M%S').\$1.csv/" *.dat

第一部分将文件名拆分为.dat后缀和后缀之前的部分;替换部件使用date命令计算的当前日期/时间,并使用ISO 8601日期/时间格式的变体进行格式化。它添加了固定前缀,新日期/时间,旧前缀和新后缀 - 并应用于当前目录中的所有.dat文件。

POC

(
mkdir junk
cd junk
for file in $(seq -f 'XXIN123.2014010118000%.0f.dat' 0 9); do cp /dev/null $file; done
ls -1
rename "s/(.*)\.dat$/XXX.123_456.$(date +'%Y%m%d%H%M%S').\$1.csv/" *.dat
ls -1
)

输出

XXIN123.20140101180000.dat
XXIN123.20140101180001.dat
XXIN123.20140101180002.dat
XXIN123.20140101180003.dat
XXIN123.20140101180004.dat
XXIN123.20140101180005.dat
XXIN123.20140101180006.dat
XXIN123.20140101180007.dat
XXIN123.20140101180008.dat
XXIN123.20140101180009.dat
XXX.123_456.20140101181530.XXIN123.20140101180000.csv
XXX.123_456.20140101181530.XXIN123.20140101180001.csv
XXX.123_456.20140101181530.XXIN123.20140101180002.csv
XXX.123_456.20140101181530.XXIN123.20140101180003.csv
XXX.123_456.20140101181530.XXIN123.20140101180004.csv
XXX.123_456.20140101181530.XXIN123.20140101180005.csv
XXX.123_456.20140101181530.XXIN123.20140101180006.csv
XXX.123_456.20140101181530.XXIN123.20140101180007.csv
XXX.123_456.20140101181530.XXIN123.20140101180008.csv
XXX.123_456.20140101181530.XXIN123.20140101180009.csv

如果您需要我的rename命令版本,请发送电子邮件(当然,这是我使用的,但它基于原始代码)。

如果你决定必须使用Perl来创建新的时间戳,你必须更加努力(并且非常非Perlish来重新发明轮子)。

答案 1 :(得分:0)

也许以下内容会有所帮助:

use strict;
use warnings;
use File::Basename;
use File::Copy;
use POSIX;

my $dir         = '/home/sd1/a1';
my $destdir     = '/home/sd1/a1/destination';
my $newpat      = 'XXX.123_456';
my $oldpat      = 'MHINOCC13';
my $currenttime = strftime( "%Y%m%d%H%M%S", localtime );

for my $currFile (<$dir/*.dat>) {
    my $fileName = basename($currFile);
    next unless $fileName =~ /^$oldpat-\d+-\d+[.]dat$/;

    $fileName =~ s/dat$/csv/;
    my $destFile = "$destdir/$newpat-$currenttime-$fileName";

    print "Copying: $currFile ->  $destFile\n";

    if ( copy( $currFile, $destFile ) ) {
        print "Success!\n\n";
    }
    else {
        warn "Copy failed: $!\n\n";
    }
}

这使用glob<>)来读取源目录。在for循环中,File::Basename提取文件名,并使用正则表达式进行检查,以仅过滤所需的文件。接下来,文件名将更改为您想要的格式,然后使用File::Copy将源文件复制到目标目录中的新文件名。

请注意copy例程将覆盖目标目录中任何同名的现有文件,因此使用此脚本需要您自担风险。