Perl搜索文件并在复制到不同目录时重命名它们

时间:2015-04-14 11:17:50

标签: perl

我尝试使用以下代码搜索.txt文件,并在将其复制到不同目录时重命名。

#!/bin/perl
use File::Basename;
@txtfiles = <*/*.txt>;
foreach my $file(@textfiles){
    $dir = dirname($file);
    $file = basename($file);
    $file =~ s/(\d+)/$dir/; //renaming number with $dir
`mkdir -p summary` unless -d summary;
`cp $file summary`;
}

上面的代码给出了错误,说明没有要复制的文件但是每行的print语句都正确显示(重命名的文件名)

2 个答案:

答案 0 :(得分:1)

<强> 真是没有!

不要使用系统命令 - 尤其是因为您可以使用Perl命令。

`mkdir -p summary` unless -d summary;
`cp $file summary`;

使用 Perl 命令!

use File::Copy;       # Standard Perl Module. USE IT!
...
mkdir 'summary' unless -d 'summary';   # No need for `-p`
copy $file, 'summary';

这是一个经过修改的脚本:

#! /usr/bin/env perl

use strict;
use warnings;
use feature qw(say);

# use File::Basename;  -- No need for this in this version
use File::Copy;

# What files do you want to find?
# Do you want to find the immediate files or the
# files in the subdirectories?

my @text_files = glob('*.txt');  # Immediate files only

mkdir 'summary' if not -d 'summary';   # Make this dir before the loop
for my $file ( @text_files ) {
    next unless -f $file;              # Make sure this is a file you want to copy!
    #
    # No need for 'dirname' and 'basename' with '*.txt' glob
    #
    if ( not copy $file, 'summary' ) { # Check the outcome of this command.
        warn qq(Could not copy file "$file" to "summary".);
    }
}

如果您需要复制子目录中的文件而不是仅在直接目录中,请告诉我们。也许您可以使用make_tree中的File::Pathfind中的File::Find的Perl版本。这些是所有Perl安装都具有的标准Perl模块。


附录

  

我不想要当前目录。这些文件位于一个目录中,即foo/text_v0001.txtfoo/text_v0002.txtfoo_au/text_v0003.txtfoo_au/text_v0004.txt继续....我想用目录名替换数字,例如foo/text_v0001.txt应重命名为text_foo.txtfoo/text_v0002.txt应重命名为text_foo.txt(因为在同一文件夹中我们无法使用相同的名称文件,因此我们可以添加第2部分和第二部分结尾文件即text_fooPart2.txt)。

最后一部分是doozy,这也是一项新要求。我需要验证一个文件是否已经存在同名,如果存在,我需要确保找到下一个可用名称。

如果我发现文件已经存在,我将循环递增一个重复的文件计数器,直到找到一个尚不存在的文件名。

#! /usr/bin/env perl

use strict;
use warnings;
use feature qw(say);

use File::Basename;
use File::Copy;
use File::Glob;                        # Improved Glob matching.

use constant {
    DIRECTORY           => 'summary',
};

# What files do you want to find?
# Do you want to find the immediate files or the
# files in the subdirectories?

#
# Let's do a more sophisticated pattern making sure we're catching
# the files we want.
#
my @text_files = glob('*/*.txt');      # Subdirectories only
mkdir DIRECTORY if not -d DIRECTORY;   # Make this dir before the loop

for my $file ( @text_files ) {
    my $dir_name  = dirname $file;
    my $file_name = basename $file;
    say "DEBUG: On '$file'.";
    #
    # Let's make sure that the file name matches the expected
    # pattern. If the substitution doesn't succeed, we assume
    # this file shouldn't be copied, and skip it.
    #
    # I'm serching for a file that has the suffix '_vxxxx.txt' where
    # 'xxxx' is some number. I remove the number and the letter `v`,
    # and add in the directory name.
    #
    if ( not $file_name =~ s/_v(\d+)\.txt$/_$dir_name.txt/ ) {
        warn qq("$dir_name/$file_name" has not been copied.");
        next;
    }
    #
    # If the name matches, make sure it's a file
    #
    if ( not -f $file ) {
        warn qq("$file" is not a file and wasn't copied.");
        next
    }
    #
    # Now make sure file name is unique
    #
    if ( -f DIRECTORY . "/$file_name" ) {         # File name already exists
        say qq(DEBUG: Duplicate File '$file_name' detected!);
        my $dup_file_counter = 2;
        ( my $file_no_suffix = $file_name ) =~ s/\.txt$//;
        #
        # Find a non-matching name
        #
        for (;;) {
            my $new_file_name = $file_no_suffix . "_part_$dup_file_counter.txt";
            say "DEBUG: New file name '$new_file_name'";
            say qq(DEBUG: if ( not -e @{[DIRECTORY]} . "/$new_file_name" ) { );
            if ( not -e DIRECTORY . "/$new_file_name" ) {
                $file_name = $new_file_name;
                last;
            }
            else {
                $dup_file_counter += 1;
            }
        }
    }


    if ( not copy $file, DIRECTORY . "/$file_name" ) { # Check the outcome of this command.
        warn qq(Could not copy file "$file" to directory ") . DIRECTORY . qq(".);
    }
}

答案 1 :(得分:0)

在您使用@textfiles而非@txtfiles的循环中。使用strict

#!/usr/local/bin/perl
use File::Basename;
use strict;
use warnings;


my @txtfiles = glob("*.txt");
foreach my $file(@txtfiles){
     my $dir = dirname($file);
     $file = basename($file);
     $file =~ s/(\d+)/$dir/; # renaming number with $dir
     `mkdir -p summary` unless -d "summary";
     `cp $file summary`;
}