【问题标题】:Renaming two files in multiple folders by adding suffix and prefix通过添加后缀和前缀重命名多个文件夹中的两个文件
【发布时间】:2018-04-22 15:24:36
【问题描述】:

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

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

如何在 shell 或 Perl 中做到这一点?

【问题讨论】:

  • 请展示你的努力。
  • IT1IT2 前缀背后的想法是什么?
  • IT1 和 IT2 是一个测试用例的两次迭代。
  • 我正在关注 O/P [root@localhost]# python test.py > /home/abc/test.py(5)() -> 对于子目录中的子目录:( pdb)
  • @Raj2015 不要在 cmets 中发布代码。 Edit您的问题并在此处包含代码。

标签: shell perl


【解决方案1】:

试试这个,使用 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

【讨论】:

  • 谢谢你..实际上有多个文件夹,如 ABC、DEF、GHI....XYZ。在每个文件夹中只有两个文件存在。这两个文件中的每一个都是唯一的..假设ABC中存在123.jpg,456.jpg,然后在XYZ文件夹中存在987.jpg和675.jpg。所以我想将唯一文件夹中存在的所有这些唯一文件重命名为上述语法。像123。 jpg 应重命名为 IT1_ABC_123.v2.jpg 和 456.jpg 应重命名为 IT2_ABC_456.v2.jpg。
  • find 将贯穿任何子文件夹。将find 更改为find ???(是的,三个问号)以遍历名称为三个字符的任何文件夹。您可以将 123|456 替换为 \d{3} 以匹配任何三位数字,而不仅仅是 123 和 456。(关于 "Thanks for this"...upvote 是 stackoverflow.com 上最好的感谢,我的答案左上角数字上方的向上箭头符号 ;-)
  • 嗨 Kjetil..我遇到语法错误.. find???|perl -nlE's((.*)/(.+))/((d{3}).jpg), $1/IT@{[++$n]}_$3_$4,&&say"$&\n$_\n"' find???|perl -nlE's((.*)/(.+))/( (d{3}).jpg),$1/IT@{[++$n]}_$3_$4, and rename$&,$_' bash-3.2# perl abc.pl 语法错误在 abc.pl 行4、在"(."附近执行abc.pl由于编译错误而中止。
  • Weeeeell,你在??? 之前遗漏了一个空格,在第一个s 后面遗漏了一个逗号,也许还有更多。 (在我上面的答案中添加了一些东西)
  • bash-3.2# find|perl a.pl find: 参数数量不足 find: [-H | -L] path-list predicate-list 还是报错:(
【解决方案2】:

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

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

【讨论】:

  • :当我在父文件夹下有两个或多个文件夹时,它会将文件重命名为 IT1、IT2、IT3、IT4.IT5 等。但我的要求是父文件夹下的每个子文件夹,只有两个文件,它们应该重命名为 IT1 和 IT2。我不希望 IT3 和 IT4 用于第二个子文件夹。
  • :你能回答上面的问题吗?
  • 嗨@Raj2015,我已经更新了我的答案,以显示如何通过将当前文件的目录路径与上一个循环中的目录路径进行比较来重置计数器。我只进行了基本检查以查看它是否运行,因此我建议先对其进行彻底测试。
  • 嗨@Interduo 我执行了上面的代码。它适用于第一个文件夹,但对于第二个文件夹,我看到它将文件重命名为 IT3 和 IT1。
  • 嗨@Raj2015,您可能需要在循环遍历@fileset 数组之前对其进行排序。否则,您将不得不仔细查看$previous_dir$parent_dir 之间的比较。您可能需要使用正则表达式而不是 ne 运算符来使匹配按预期工作。
猜你喜欢
  • 2014-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-16
  • 2021-04-02
  • 2011-06-14
  • 1970-01-01
相关资源
最近更新 更多