批量重命名目录中的文件名

时间:2011-11-30 14:02:18

标签: perl bash sed awk

我有一些名字如下的文件:

01_dpm_gsi_182.sl5
02_dpm_devel_gsi_182.sl5
03_DPM_DSI_181.sl5
04_globus_httpd_122.sl5
05_globus_httpd_client_cgi_132.sl5

如何重命名这些文件,以便我得到以下内容:

01_dpmgsi_s2011e01.sl5
02_dpmdevelgsi_s2011e02.sl5
....
....

我最近的建议如下:

#!/usr/bin/perl -n

if (/^([^_]+)_(.+)_([^.]+)([.].+)$/) {
    my $s = $&;
    my $x = $1;
    my $y = $2;
    my $z = 2011;
    my $e = $4;

    $y =~ s/_//g;

    print "mv $s ${x}_${y}_s${z}e$x$e\n"
}

然后像这样使用它:

# ls | perl -n reName.pl > output
# bash ./output

有没有更好的方法或单行做这个,可能使用sed / awk?干杯!!

5 个答案:

答案 0 :(得分:6)

没有必要使用bash脚本来mv文件,perl可以这样做。下面的脚本使用File::Copy来实现此目的。我已经注释掉了执行移动的行,因此可以先使用输入来测试脚本。

<强>代码:

use strict;
use warnings;
use v5.10;

#use File::Copy;
my $year = 2011;
for (@ARGV) {
    my ($pre, @p) = split /_/;
    my $ext = pop @p;
    $ext =~ s/.*\./s${year}e$pre./;
    my $new = join '_', $pre, (join '', @p), $ext;
    say "old: $_";
    say "new: $new";
    say "------";
    #move $_, $new or die $!;
}

<强>用法:

perl script.pl *.sl5

如果您没有版本5.10,请与say交换print并添加换行符。

<强>输出:

old: 01_dpm_gsi_182.sl5
new: 01_dpmgsi_s2011e01.sl5
------
old: 02_dpm_devel_gsi_182.sl5
new: 02_dpmdevelgsi_s2011e02.sl5
------
old: 03_DPM_DSI_181.sl5
new: 03_DPMDSI_s2011e03.sl5
------
old: 04_globus_httpd_122.sl5
new: 04_globushttpd_s2011e04.sl5
------
old: 05_globus_httpd_client_cgi_132.sl5
new: 05_globushttpdclientcgi_s2011e05.sl5

答案 1 :(得分:2)

这个GNU sed解决方案可能适合您:

 sed 'h;s/[^_.]*\././;s/_//2g;s/^\(\([^_]*\)_[^.]*\)\./\1_s2011e\2e./;x;G;s/\(.*\)\n/mv -v \1 /' file

说明:

将原始文件名存储在保留空间(HS)中。删除文件扩展名前面的数字。删除除第一个_之外的所有内容。使用分组,反向引用和添加的文本创建新文件名。交换到HS。附加新文件名。添加mv -v命令并删除嵌入的\n

如前所述,文件名可能会让你失望 - 请注意!

答案 2 :(得分:1)

您不需要单独的bash脚本来进行重命名。 Perl有一个内置的rename函数。有关文档,请参阅http://perldoc.perl.org/functions/rename.html

我不打算对正则表达式发表评论。它可能有所改进,但只要它正常工作,我认为没有必要改变它。

答案 3 :(得分:1)

这种事has been covered before,答案是使用现有的重命名用户而不是自己编写。

答案 4 :(得分:0)

好吧,你要求一个单行:

ls |xargs -n1|awk -F'[_.]' '{idx=$1;nf=$1"_";for(i=2;i<NF-1;i++)nf=nf$i; nf=nf"_s2011e"idx"."$NF;print "mv "$0" "nf;}'

这将为您打印所有mv命令。

如果目标名称都正确,您可以检查输出。如果是,您只需在行尾添加"|sh",它就会重命名。

测试(没有| sh,看输出)

kent$  ls |xargs -n1|awk -F'[_.]' '{idx=$1;nf=$1"_";for(i=2;i<NF-1;i++)nf=nf$i; nf=nf"_s2011e"idx"."$NF;print "mv "$0" "nf;}'
mv 01_dpm_gsi_182.sl5 01_dpmgsi_s2011e01.sl5
mv 02_dpm_devel_gsi_182.sl5 02_dpmdevelgsi_s2011e02.sl5
mv 03_DPM_DSI_181.sl5 03_DPMDSI_s2011e03.sl5
mv 04_globus_httpd_122.sl5 04_globushttpd_s2011e04.sl5
mv 05_globus_httpd_client_cgi_132.sl5 05_globushttpdclientcgi_s2011e05.sl5