2011-11-30 237 views
3

我有這樣的名字有些文件的文件名:批量重命名目錄中的

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

回答

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,交換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 –

1

您不需要單獨的bash腳本來執行重命名。 Perl有一個內置的rename函數。有關文檔,請參閱http://perldoc.perl.org/functions/rename.html

我不打算評論正則表達式。改善它可能是可能的,但只要它正常工作,我不認爲有任何需要改變它。

0

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

1

這種事情has been covered before,答案是使用現有的重命名utiliy而不是自己編寫。

+1

文件名操作OP要求提供一個有點複雜的正則表達式。我認爲Perl腳本在這裏完全適用。 – Jonathan

+0

@Jonathan:這就是爲什麼你使用Perl編寫的'rename',如鏈接答案中提到的那個。 – ninjalj

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讓我頭暈目眩。 –

+0

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

2

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