批量重命名目录中的

问题描述:

我有这样的名字有些文件的文件名:批量重命名目录中的

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?干杯!!

有没有必要使用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,交换sayprint并添加一个换行符。

输出:

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 
+0

+1不需要使用bash脚本 – Toto

+0

简单易懂! +1 –

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

我不打算评论正则表达式。改善它可能是可能的,但只要它正常工作,我不认为有任何需要改变它。

OK,你问一个班轮:

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 
+0

解析用于处理文件的'ls'输出?这肯定会打破空间,不寻常的文件名等。这不是一个好习惯。 – Sorpigal

+0

@Sorpigal检查OP的示例文件。和。 awk之前的部分只是为了展示它的工作原理。重点是awk部分,对吧?你当然可以使用find,xargs等来处理空格。但不是这个问题的重点。 – Kent

+0

@Kent是不是可以简单地使用glob? – TLP

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

+1

文件名操作OP要求提供一个有点复杂的正则表达式。我认为Perl脚本在这里完全适用。 – Jonathan

+0

@Jonathan:这就是为什么你使用Perl编写的'rename',如链接答案中提到的那个。 – ninjalj

这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让我头晕目眩。 –

+0

+2相同(但WOW !!) – MacUsers

omg,从不分析ls的输出或构建由shell重新评估的查询。解析一个文件列表(由ls输出)不可能在空白(或$ IFS变量中的任何内容)的情况下得到正确的结果,因此在任何时候都是一个尴尬的解决方案。同样,构建正确逃脱shell命令行几乎是不可能的。

为了保持与壳牌(这是这个任务仍然是一个很好的工具),使用通配符的文件,其中正确拆分参数:

for i in ./* 
do 
    firstpart=${i%%_*} 
    num=${firstpart#./} 
    middlepart=${i#*_} 
    middlepart=${middlepart%_*} 
    middlepart=`printf %s "$middlepart" | tr -d _` 
    lastpart=s2011e"$num".sl5 
    echo mv "$i" "${firstpart}_${middlepart}_${lastpart}" 
done 

实际执行,删除echo的最后一行。

+0

+1,不需要perl脚本。 – Sorpigal

+0

@Jo所以:+1关于'ls'输出的注释,但在这种特殊情况下,这没有什么坏处。我的所有时间最喜欢的shell脚本的另一个+1。 – MacUsers