通过添加后缀和前缀重命名多个文件夹中的两个文件

时间:2018-04-22 15:24:36

标签: shell perl

我有多个文件夹,其中有两个文件。

例如,文件夹123.jpg下的456.jpgABC。我想将文件重命名为IT1_ABC_123.v1.jpgIT2_ABC_456.v1.jpg。同样,其他文件夹有两个文件。

如何在shell或Perl中执行此操作?

2 个答案:

答案 0 :(得分:0)

尝试使用shell perl:

mkdir /tmp/test; cd $_
mkdir ABC DEF
touch {ABC,DEF}/{123,456}.jpg   #creates four files, two in each directory
find|perl -nlE's,((.*)/(.+))/((123|456).jpg),$1/IT@{[++$n]}_$3_$4,&&say"$&\n$_\n"'

./ABC/123.jpg
./ABC/IT1_ABC_123.jpg

./ABC/456.jpg
./ABC/IT2_ABC_456.jpg

./DEF/123.jpg
./DEF/IT3_DEF_123.jpg

./DEF/456.jpg
./DEF/IT4_DEF_456.jpg

现在,在确认这是您想要的之后,将say替换为rename

find|perl -nlE's,((.*)/(.+))/((123|456).jpg),$1/IT@{[++$n]}_$3_$4, and rename$&,$_'

新文件名:

find -type f
./ABC/IT1_ABC_123.jpg
./ABC/IT2_ABC_456.jpg
./DEF/IT3_DEF_123.jpg
./DEF/IT4_DEF_456.jpg

这将找到123.jpg或456.jpg的文件名并重命名。

s,,,是搜索替换,它返回1(它所做的更改次数),这又导致and的右侧(重命名)。

与123.jpg或456.jpg不匹配的文件名未重命名,因为s,,,将返回0而and是“短切”,因为它在逻辑上不可能是真的假(0)左侧。所以重命名是执行。

此变体也是如此,但可能更容易阅读:

find|perl -nlE 'rename$&,$_ if s,((.*)/(.+))/((123|456).jpg),$1/IT@{[++$n]}_$3_$4,'

我发现这种模式在许多大规模重新命名的情况下都很有用。此外,存在用于使用GUI进行大规模重命名的专用软件,对于某些人来说可能更容易使用。

重写为程序abc.pl,它可能是:

#!/usr/bin/perl
while(<>){
  chomp;
  next if not s,((.*)/([A-Z]{3}))/(\d{3}\.jpg),$1/IT@{[++$n]}_$3_$4,;
  print "Found:    $&\nNew name: $_\n\n";
 #rename $&, $_;
}

执行命令

find|perl abc.pl

答案 1 :(得分:0)

您可以使用File::FindFile::BasenameFile::Copy模块在​​核心Perl中执行此操作。您可以使用下面的脚本进行测试。在您使用&#34;移动&#34;取消注释行之前,它不会进行任何更改。功能

#! perl

use strict;
use warnings;

use File::Basename;
use File::Copy;
use File::Find;

my $root_dir = '/path/to/main/folder';

# Recursively searches for all files below the $root_dir
my @fileset;
find(
    sub {

        # Get the absolute file path
        my $path = $File::Find::name;

        # Only capture the path if not a directory
        # You can add any number of conditions here
        if (!-d $path) {
            push @fileset, $path;
        }
    },
    $root_dir
);

# set the IT counter in new file name
my $int = 1;

# list of all possible file suffixes to have fileparse() look for. It will 
# capture the end of the file path verbatim (including the period) if it's 
# in this array 
my @suffixes = ('.jpg', '.txt');

my $previous_dir;
foreach my $old_path (@fileset) {

    # split apart the basename of the file, the directory path, and the file suffix
    my ($basename, $parent_dir, $suffix) = fileparse($old_path, @suffixes);

    # strip off trailing slash so fileparse() will capture parent dir name correctly
    $parent_dir =~ s{[/]$}{};

    # capture just the name of the parent directory
    my $parent_name = fileparse($parent_dir);

    # Assemble the new path
    my $new_path = $parent_dir . '/IT' . $int . '_' 
                 . $parent_name . '_' . "$basename.v1" . $suffix;

    # Move the file to rename (this is safer than using rename() for cross-platform)
    # move $old_path, $new_path;

    print "OLD PATH: $old_path\n";
    print "NEW PATH: $new_path\n\n";

    # Reset counter when dir changes
    if (!$previous_dir) {
        $previous_dir = $parent_dir; # set previous_dir on first loop
    }
    elsif($previous_dir ne $parent_dir) {
        $previous_dir = $parent_dir; # update previous_dir to check next loop
        $int = 0; # reset counter
    }

    $int++; # iterate the counter
}

编辑2018-07-12:我已经更新了答案,通过评估当前路径和前一个循环中使用的路径来显示如何在目录更改时重置计数器相应地更新。这未经过测试,因此可能需要进行一些调整。

给定abc / def示例,输出应该如下所示:

OLD PATH: /path/to/main/folder/abc/123.jpg
NEW PATH: /path/to/main/folder/abc/IT1_abc_123.v1.jpg

OLD PATH: /path/to/main/folder/abc/456.txt
NEW PATH: /path/to/main/folder/abc/IT2_abc_456.v1.jpg

OLD PATH: /path/to/main/folder/def/123.jpg
NEW PATH: /path/to/main/folder/def/IT1_def_123.v1.jpg

OLD PATH: /path/to/main/folder/def/456.jpg
NEW PATH: /path/to/main/folder/def/IT2_def_456.v1.jpg