Python 按相反顺序批量重命名目录

Python 按相反顺序批量重命名目录,python,linux,bash,sed,Python,Linux,Bash,Sed,我有一堆(700多个)目录,它们的命名方式如下 1 - *random*name*1* 2 - *random*name*2* ... 725 - *random*name*725* 前导号码(1-725)都是目录名的一部分 也就是说:所有目录名都以数字开头,后跟[space][dash][space],后跟一些文本。 我想批量重命名它们,以便将它们命名为以下名称: 1 - *random*name*725* 2 - *random*name*724* ... 725 - *random*na

我有一堆(700多个)目录,它们的命名方式如下

1 - *random*name*1*
2 - *random*name*2*
...
725 - *random*name*725*
前导号码(1-725)都是目录名的一部分

也就是说:所有目录名都以数字开头,后跟[space][dash][space],后跟一些文本。

我想批量重命名它们,以便将它们命名为以下名称:

1 - *random*name*725*
2 - *random*name*724*
...
725 - *random*name*1*
我只想“反转”目录名的数字部分。基本上,我希望在“1-”之后的文本跟在“725-”之后,在“2-”之后的文本跟在“724-”之后,依此类推

最简单的方法是什么?我在linux上


注意:随机*名称*都是不同的,只是为了举例说明。

使用
perl的一种方法。代码被注释

script.pl的内容

#!/usr/bin/env perl

use warnings;
use strict;
use File::Basename qw|basename|;

die qq{Usage: perl $0 <real|trial>\n} unless @ARGV == 1;

my $real = $ARGV[0] eq q|real| ? 1 : 0;

## Filter filenames from the directory that match criteria of OP.
my @files = grep { -d $_ && m/\A(\d+)\s-\s.*\1/ } map { basename $_ } <./*>;

## Get numbers in reverse mode to substitute them later in filenames .
my @nums = map { m/\A(\d+)/; $1 || 0 } reverse @files;

## Process all files, change the number of the file and rename it.
for my $file ( @files ) { 
    (my $new_file = $file) =~ s/\A(\d+)/shift @nums/e;

    if ( $real ) { 
        rename $file, $new_file or warn qq|WARN: Couldn't rename "$file"\n|;
    }   
    else {
        printf qq|%s\n|, qq|rename "$file" "$new_file"|;
    }   
}
具有以下输出:

1 - file1file
2 - fi2le
3 - fileeee3
4 - fou4r
5 -  donttouch
6 -  donttouch5either
script.pl
1 - fou4r
2 - fileeee3
3 - fi2le
4 - file1file
5 -  donttouch
6 -  donttouch5either
script.pl
运行脚本:

perl script.pl
再次列出董事:

具有以下输出:

1 - file1file
2 - fi2le
3 - fileeee3
4 - fou4r
5 -  donttouch
6 -  donttouch5either
script.pl
1 - fou4r
2 - fileeee3
3 - fi2le
4 - file1file
5 -  donttouch
6 -  donttouch5either
script.pl

EDIT:评论中有一个建议,让试用先于实际的,所以我添加了一个参数
real
trial
。使用第一个选项,它将进行真正的更改,而使用第二个选项,它将
打印
以输出真正的命令,但不运行它们。现在按如下方式运行脚本:

perl script.pl real


如果这个awk解决方案适合您

命令:

这里5是硬编码的,在您的情况下是725.:)当然可以由wc-l设置,但我有点懒

测试:


让我们首先模拟一些文件名:

$ printf 'kjdfh8\nskdjfh9\nckjhv10\naskjdh11\n'
kjdfh8
skdjfh9
ckjhv10
askjdh11
然后把它们穿过管道:

$ printf 'kjdfh8\nskdjfh9\nckjhv10\naskjdh11\n' | sed 's/[^0-9]*\(.*\)/\1 &/' | sort -nr | cut -d\  -f2-
askjdh11
ckjhv10
skdjfh9
kjdfh8
这是怎么回事?其实很简单。首先,我们使用
sed
将任何数字内容的副本放在行的开头。接下来,我们分类。最后,我们使用
cut
去除行首的数字。瞧

现在。。。这正好颠倒了顺序。这是你问题中的一个问题,但你的最终目标是重新命名。我们可以使用另一个也是while循环的管道来扩展上面的列表。这次我将把东西隔开以便阅读

#!/bin/bash

n=0
printf 'kjdfh8\nskdjfh9\nckjhv10\naskjdh11\n' \
| sed 's/[^0-9]*\(.*\)/\1 &/' | sort -nr | cut -d\  -f2- \
| while read file; do
    base="${file/[0-9]*/}"
    ((n++))
    printf 'mv "%s" "%s%s"\n' "$file" "$base" "$n"
  done
这个while循环读取我们在上面创建的文件列表。它通过删除文件名中从第一个数字开始的所有内容来获取“基”。它增加一个计数器(用于新名称),然后打印带有旧文件名、基和计数器的
mv
命令

同样,这个脚本的输出是一组
mv
命令,您可以通过一个shell进行管道传输

显然,要在文件中使用此命令,需要将初始的
printf
命令替换为生成文件列表的命令

注意:以这种方式处理文件名通常是不可取的,因为可能会在文件名中出现意外或特殊字符(甚至空格),从而打乱您的计划。只有当你确信自己理解它时,才能这样做。

这:

find /path/to/the/directories/location/ -depth -exec mv '{}' $(basename '{}')$(echo $(date "+%H%M%S%N")) \;

“随机名称”代表所有725个目录的相同名称,还是不同的名称?您尝试过什么?我会先看看
os
copy
模块,再看看list的
reverse()
方法。使用
导入glob、re、shutil
。因此,我并不真正编写脚本,只需获取所有文件名(glob),创建一个执行我想要的操作的正则表达式,循环文件名并对其进行转换,当所有这些都起作用时,将实际的重命名命令添加到循环中,所有随机名称都是不同的吗?否则,您可能会遇到冲突问题,例如当
*foo*1*
*foo*725*
两者最初都存在时。如果输入名称列表是
abc1
def2
ghi3
,则是所需的结果
abc3
def2
ghi3
,还是
ghi3
abc1
?这个问题不太清楚。谢谢,我们正在取得进展。我想你遇到的麻烦比需要的多。请注意,所有目录名都以数字开头,后跟[space][dash][space],后跟一些我不想修改的文本(即使它包含数字)。我想从您的示例中看到的结果是
1-fou4r,2-fileeee3,3-fi2le,4-file1file
。对不起,perl对我来说就像胡言乱语,所以我不能自己修改你的代码。谢谢!我已经在测试目录中进行了测试,它可以正常工作。有没有办法先在实际目录上进行“试运行”,而不做任何更改?正如您在实际执行“mv”之前在控制台中“echo mv”一样?@zigamilek:编辑了我的答案以允许该选项。谢谢。但我觉得有些东西不见了。试用版不会打印aynthing,real run不会重命名aynthing。@zigamilek:脚本和以前一样适用于我。你确定你正在用你的问题的相同规格运行它吗?它不会打印任何内容,因为它找不到任何包含您的详细信息的目录。请再检查一遍。谢谢您的尝试。不幸的是,它不能像我希望的那样工作。请注意,所有目录名都以数字开头,后跟[space][dash][space],后跟一些文本。文本每次都不同,不一定包含数字。
$ printf 'kjdfh8\nskdjfh9\nckjhv10\naskjdh11\n' | sed 's/[^0-9]*\(.*\)/\1 &/' | sort -nr | cut -d\  -f2-
askjdh11
ckjhv10
skdjfh9
kjdfh8
#!/bin/bash

n=0
printf 'kjdfh8\nskdjfh9\nckjhv10\naskjdh11\n' \
| sed 's/[^0-9]*\(.*\)/\1 &/' | sort -nr | cut -d\  -f2- \
| while read file; do
    base="${file/[0-9]*/}"
    ((n++))
    printf 'mv "%s" "%s%s"\n' "$file" "$base" "$n"
  done
find /path/to/the/directories/location/ -depth -exec mv '{}' $(basename '{}')$(echo $(date "+%H%M%S%N")) \;