2013-01-09 85 views
3

我正在尋找批量重命名當前目錄中的文件,並從文件名末尾刪除某些字符串。使用bash和Perl批量重命名文件基於文件名

樣品:

foo-bar-(ab-4529111094).txt 
foo-bar-foo-bar-(ab-189534).txt 
foo-bar-foo-bar-bar-(ab-24937932201).txt 

輸出應該是這樣的:

foo-bar.txt 
foo-bar-foo-bar.txt 
foo-bar-foo-bar-bar.txt 

我想在每個文件名 的年底將字符串-(ab-2492201)知道數字的長度可以變化。

Perl正則表達式優於模塊,並且不使用任何實用程序,對於bash oneliner命令是高度優先的。

如何在Linux上的Perl和Bash Shell中完成該操作?有興趣知道兩種解決方案。

+0

爲什麼你不希望使用任何Perl模塊? – Borodin

+0

在我的主腳本中插入代碼之後,可以在多臺機器上進行移植,因此並非每臺機器都必須安裝模塊依賴關係。 – SilverShadow

+0

perl「核心」模塊非常多,應該可以在任何標準的Perl安裝中使用。一旦它們是'File :: Find',但它似乎不是您的問題所必需的。 – Borodin

回答

4

在bash,你可以寫這樣的:

for file in *-\(ab-[0-9]*\)*; do 
    newfile="${file/-(ab-[0-9]*)/}" 
    mv "$file" "$newfile" 
done 
+0

工作完美像我想要的其他解決方案沒有,保存我的時間,非常感謝! – SilverShadow

5

嘗試:

$ rename 's/-\(ab-\d+\)(?=\.txt$)//' *.txt 

有Perl編寫的rename命令。它的第一個參數是描述如何轉換文件名的Perl代碼。您可以在您自己的Perl程序或單行程序中使用相同的s///命令。

如果這不起作用,請嘗試prename而不是rename;在某些系統上安裝了另一個不基於Perl的rename命令,在這種情況下,Perl可能被稱爲prename

+0

沒有工作的伴侶,但我仍然在努力,謝謝 – SilverShadow

+0

奇怪。我只是在你的問題中創建了具有確切名稱的文件,然後粘貼到上面的'rename'命令中,並且它工作正常。當你嘗試時發生了什麼?有沒有錯誤信息?如果你在'rename'命令中加入了'-v'選項,它是否會提供任何輸出? – Smylers

+1

顯然有不止一個叫做「重命名」的命令;一些Linux發行版帶有一個非perl版本,其工作方式不同。見:http://stackoverflow.com/questions/22577767/get-the-perl-rename-utility-instead-of-the-built-in-rename –

1

一種更簡單,更短的(更好:)?)rename正則表達式:

rename '[email protected]\(.*?\)@@' foo*.txt 
+1

試試吧,謝謝:)) – SilverShadow

+0

沒有工作,對不起,請注意,字符串「foo」在文件名的開頭可以是任何類似多個單詞用短劃線分隔 - – SilverShadow

+0

What @sputnick寫的將與文件名開頭的任何內容,只要它有一個連字符,一個開頭的paren,以及(稍後的某個點)一個關閉的paren。你有沒有嘗試創建你在問題中提到的確切文件名,看看它是否適用於這些? – Smylers

2

當你說當前目錄下,你的意思是的當前目錄,或者任何地方或者beaneath當前目錄及其後代?

File::Find是做後者的簡單方法,也是一個核心模塊,所以不需要安裝。像這樣:

use strict; 
use warnings; 

use autodie; 

use File::Find; 

find(\&rename, '.'); 

sub rename { 
    return unless -f; 
    my $newname = $_; 
    return unless $newname =~ s/-\(ab-[0-9]+\)(\.txt)$/$1/i; 
    print "rename $_, $newname\n"; 
} 

更新

這項計劃將重命名所有與只在當前目錄給定的文件名模式的文件。

請注意,最初的open循環僅用於爲重命名創建示例文件。

use strict; 
use warnings; 

use autodie; 

open my $fh, '>', $_ for qw(
    foo-bar-(ab-4529111094).txt 
    foo-bar-foo-bar-(ab-189534).txt 
    foo-bar-foo-bar-bar-(ab-24937932201).txt 
); 

for (glob '*.txt') { 
    next unless -f; 
    my $newname = $_; 
    next unless $newname =~ s/-\(ab-[0-9]+\)(\.txt)$/$1/i; 
    print "rename $_, $newname\n"; 
    rename $_, $newname; 
} 

輸出

rename foo-bar-(ab-4529111094).txt, foo-bar.txt 
rename foo-bar-foo-bar-(ab-189534).txt, foo-bar-foo-bar.txt 
rename foo-bar-foo-bar-bar-(ab-24937932201).txt, foo-bar-foo-bar-bar.txt 
+0

當前目錄只有一個級別,沒有子目錄。我會嘗試,謝謝 – SilverShadow

+0

這段代碼將下降到子目錄,是*不*你想要的。 – Borodin

+0

好的,謝謝你的時間兄弟 – SilverShadow

1

檢查:

ls -1 | nawk '/foo-bar-/{old=$0;gsub(/-\(.*\)/,"",$0);system("mv \""old"\" "$0)}' 

> ls -1 foo* 
foo-bar-(ab-4529111094).txt 
foo-bar-foo-bar-(ab-189534).txt 
foo-bar-foo-bar-bar-(ab-24937932201).txt 

> ls -1 | nawk '/foo-bar-/{old=$0;gsub(/-\(.*\)/,"",$0);system("mv \""old"\" "$0)}' 

> ls -1 foo* 
foo-bar-foo-bar-bar.txt 
foo-bar-foo-bar.txt 
foo-bar.txt 
> 

詳細解釋檢查here