如何在目录下的所有文件名前添加前缀?

4
我正在尝试在所有目录及其子目录中,为所有*.bmp文件的名称添加一个字符串前缀(reference_)。第一次运行silk脚本时,它将创建目录和子目录,并在每个子目录下以.bmp扩展名存储每个移动应用程序的截屏。

当我第二次运行自动化silk脚本时,它将再次在所有子目录中创建*.bmp文件。在第二次运行脚本之前,我想要给所有*.bmp文件的名称添加一个前缀 reference_

例如:first_screen.bmp变成 reference_first_screen.bmp, 我的目录结构如下:
C:\Image_Repository\BG_Images\second
...
C:\Image_Repository\BG_Images\sixth

first_screen.bmpsecond_screen.bmp 等文件...

有人可以帮我吗?

如何在所有图像文件名前加上 reference_ 字符串?

当我第二次运行蚕丝中的Perl脚本时,它将从子目录中获取两个图像并逐像素比较它们。 我正在尝试以下代码。请指导我如何继续完成此任务。

#!/usr/bin/perl -w
&one;

&two;

sub one {

    use Cwd;

    my $dir ="C:\\Image_Repository";
    #print "$dir\n";
    opendir(DIR,"+<$dir") or "die $!\n";
    my @dir = readdir DIR;
    #$lines=@dir;
    delete $dir[-1];
    print "$lines\n";
    foreach my $item (@dir)
    {
        print "$item\n";
    }
    closedir DIR;
}

sub two {

    use Cwd;

    my $dir1 ="C:\\Image_Repository\\BG_Images";
    #print "$dir1\n";
    opendir(D,"+<$dir1") or "die $!\n";
    my @dire = readdir D;
    #$lines=@dire;
    delete $dire[-1];
    #print "$lines\n";
    foreach my $item (@dire)
    {
        #print "$item\n";
        $dir2="C:\\Image_Repository\\BG_Images\\$item";
        print $dir2;
        opendir(D1,"+<$dir2") or die " $!\n";
        my @files=readdir D1;
        #print "@files\n";  
        foreach $one (@files)
        {
            $one="reference_".$one;
            print "$one\n";
            #rename $one,Reference_.$one;
        }
    }
    closedir DIR;
}

我尝试使用'+<'模式进行打开调用,但读取和写入模式会导致编译错误。 当我运行此代码时,它显示带有前缀字符串的BG_images文件夹中的文件,但实际上它没有更新子目录中的文件。


我无法理解你在这里的问题。你的文本表达了一件事,但你的代码展示了另一件事。 - Joe Casadonte
3个回答

3
你不需要打开一个目录以进行写操作。只需使用opendir,不需要字符串中的模式部分:
opendir my($dir), $dirname or die "Could not open $dirname: $!";

然而,你不需要那个。你可以使用File::Find来列出你需要的文件列表。

#!/usr/bin/perl
use strict;
use warnings;

use File::Basename;
use File::Find;
use File::Find::Closures qw(find_regular_files);
use File::Spec::Functions qw(catfile);
my( $wanted, $reporter ) = find_regular_files; find( $wanted, $ARGV[0] );
my $prefix = 'recursive_';
foreach my $file ( $reporter->() ) { my $basename = basename( $file );
if( index( $basename, $prefix ) == 0 ) { print STDERR "$file 已经有 '$prefix'! 跳过.\n"; next; }
my $new_path = catfile( dirname( $file ), "recursive_$basename" );
unless( rename $file, $new_path ) { print STDERR "无法重命名 $file: $!\n"; next; }
print $file, "\n"; }

3
你应该使用File::Find模块来简化目录树的递归。
你应该扫描文件名并修改那些不以reference_开头的文件名,让它们以此开头。这可能需要将文件名分成目录名和文件名两部分,然后在文件名前缀加上reference_。可以使用File::Basename模块来完成这个操作。
在某个时刻,你需要决定第三次运行脚本时会发生什么。已经以reference_开头的文件会被覆盖吗?还是未添加前缀的文件会被覆盖呢?
文件没有被重命名的原因是重命名操作被注释了。记得在脚本的顶部添加use strict;(以及你已经使用的-w选项)。
如果你用一个数组@files来存储文件名(且这些文件名是基本名,所以不必使用File::Basename),那么循环可能看起来像这样:
   foreach my $one (@files)
   {
        my $new = "reference_$one";
        print "$one --> $new\n";
        rename $one, $new or die "failed to rename $one to $new ($!)";
   }

0

通过 coreutils for Windows 中的 find 工具:

$ find -iname "*.bmp" | perl -wlne"chomp; ($prefix, $basename) = split(m~\/([^/]+)$~, $_); rename($_, join(q(/), ($prefix, q(reference_).$basename))) or warn qq(failed to rename '$_': $!)"

为什么不使用以下命令:find -iname '*.bmp' -exec mv '{}' reference_'{}' ; #?我不懂Perl,所以我不知道管道的第二个末端在做什么(而且我也无法理解OP的问题...)。 - strager
@strager:考虑一下这个区别:dirname/img.bmp -> dirname/reference_img.bmp 和 dirname/img.bmp -> reference_dirname/img.bmp。 - jfs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接