我有一堆被以下列方式命名的(超过700)的目录
1 - *random*name*1*
2 - *random*name*2*
...
725 - *random*name*725*
领先的数字(1-725)是目录名称的一部分。
那就是:所有的目录名以数字开头,然后按[空格] [仪表] [空格],其次是一些文字。
我想批量重命名他们,这样他们就会被命名为以下几点:
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"|;
}
}
列出目录:
ls -1
随着下面的输出:
1 - file1file
2 - fi2le
3 - fileeee3
4 - fou4r
5 - donttouch
6 - donttouch5either
script.pl
运行该脚本:
perl script.pl
再次列出directoy:
ls -1
随着下面的输出:
1 - fou4r
2 - fileeee3
3 - fi2le
4 - file1file
5 - donttouch
6 - donttouch5either
script.pl
编辑 :有在评论中让前一个真正运行试验的建议,所以我增加了一个参数real
或trial
。 有了第一个选项会做真正的改变,而与第二个它会print
输出真正的命令,但不运行它们。 现在运行脚本,如:
perl script.pl real
要么
perl script.pl trial
让我们先来模拟一些文件名:
$ 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
命令,你可以通过管道通过的壳。
显然,在您的文件使用,您将需要更换初始printf
的东西,产生你的文件列表命令。
注意 :它通常是不可取的处理文件名以这种方式,由于意外或特殊字符(甚至是空格)在文件名中转动起来,并摆脱你的计划的风险。 只有做到这一点,如果你自信你理解它。
如果这AWK解决你合适吗?
CMD:
ls -F|grep "/$"|sort|awk 'BEGIN{FS=" - ";l=5;}{o=$0;gsub("/$","",o);gsub($1"/$",l--);if(o!=$0)printf "mv \"%s\" \"%s\"\n",o,$0 }' |sh
这里的5是硬编码,你的情况是725 :)当然,它可以通过厕所-l设置,但我升技懒惰。
测试:
kent$ tree -d
.
|-- 1 - foo1
|-- 2 - foo2
|-- 3 - foo3
|-- 4 - foo4
`-- 5 - foo5
5 directories
#this will only print the generated mv command:
kent$ ls -F|grep "/$"|sort|awk 'BEGIN{FS=" - ";l=5;}{o=$0;gsub("/$","",o);gsub($1"/$",l--);if(o!=$0)printf "mv \"%s\" \"%s\"\n",o,$0 }'
mv "1 - foo1" "1 - foo5"
mv "2 - foo2" "2 - foo4"
mv "4 - foo4" "4 - foo2"
mv "5 - foo5" "5 - foo1"
# if you pipe the generated command to "sh", they will be executed:
kent$ ls -F|grep "/$"|sort|awk 'BEGIN{FS=" - ";l=5;}{o=$0;gsub("/$","",o);gsub($1"/$",l--);if(o!=$0)printf "mv \"%s\" \"%s\"\n",o,$0 }' |sh
#result:
kent$ tree -d
.
|-- 1 - foo5
|-- 2 - foo4
|-- 3 - foo3
|-- 4 - foo2
`-- 5 - foo1
5 directories
这个:
find /path/to/the/directories/location/ -depth -exec mv '{}' $(basename '{}')$(echo $(date "+%H%M%S%N")) \;