2013-11-23 69 views
1

我今天在玩Bash腳本時偶然發現了Perl。當我試圖刪除多個文件名中的空格時,我發現了this後,這對我有很大幫助。在Bash中使用基於Perl的重命名命令

經過很多努力,我終於明白了重命名和替換命令及其語法。我想嘗試在文件名末尾用「x」取代所有「_(x)」,這是由於文件重複。但是當我嘗試自己做這件事時,它似乎並不奏效。我有三個問題用下面的代碼:

  • 爲什麼在我運行它時沒有執行任何操作?
  • 我使用重定向來顯示成功註釋爲錯誤,所以我知道發生了什麼。我做錯了什麼?
  • 經過大量的研究,我仍然沒有完全理解Bash中的文件描述符和重定向以及Perl中替代函數的語法。有人可以給我一個好的教程的鏈接?
find -name "*_(*)." -type f | \ 
    rename 's/)././g' && \ 
find -name "*_(*." -type f | \ 
    rename 's/_(//g' 2>&1 

回答

2

你要麼需要使用xargs或者你需要使用命令來執行find的能力:

find -name "*_(*)." -type f | xargs rename 's/)././g' 
find -name "*_(*." -type f | xargs rename 's/_(//g' 

或者:

find -name "*_(*)." -type f -exec rename 's/)././g' {} + 
find -name "*_(*." -type f -exec rename 's/_(//g' {} + 

在這兩種情況下,文件名將被添加到rename的命令行中。實際上,rename將不得不讀取其標準輸入來發現文件名 - 事實並非如此。

第一個find是否找到你想要的文件?模式結尾處是否需要點?正則表達式是否符合你的期望?好的,讓我們來調試其中的一些。

你可以用更復雜的正則表達式做這一切在一個命令:

find . -name "*_(*)" -type f -exec rename 's/_\((\d+)\)$/$1/' {} + 

find模式被修正爲失去一個尾隨.的要求。如果在擴展名之前插入_(x),那麼您需要"*_(*).*"作爲find的模式(並且您需要修改Perl正則表達式)。

Perl的替代需求解剖:

  • \(相匹配的開括號。
  • (開始捕獲組。
  • \d+尋找'一個或多個數字'。
  • )停止捕獲組。它是第一個也是唯一的,所以它的編號爲1.
  • \)相匹配。
  • $匹配文件名的末尾。
  • 替換中的$1將捕獲組1的值放入替換文本中。

在代碼中,所述發送2>&1從第二rename命令到標準輸出,而不是標準的錯誤的錯誤消息。這真的沒有什麼幫助。

你需要兩個單獨的教程;你不會找到一個涵蓋Bash中的I/O重定向和Perl中的正則表達式的教程。

'官方' Perl的正則表達式教程:

  • perlretut,也可作爲perldoc perlretut你的機器上。

Bash的手冊包括I/O重定向,但它是有點簡潔:

+0

謝謝,這確實讓我非常吃驚。但我仍然不明白爲什麼沒有xargs或exec在[我提到的例子]中使用(http://stackoverflow.com/questions/2709458/bash-script-to-replace-spaces-in-file-names) 。 在那裏,正則表達式之後的重命名命令足以刪除文件名中的空白。 另外,如果我與exec或xargs一起工作,這有什麼關係嗎?其中一種解決方案更適合於此目的嗎? – nst1nctz

+0

它取決於'rename'或'prename'命令的定義。有些版本可能每行讀取一個文件名;我有的版本(最初從駱駝書第一版中選擇)就是這樣做的。如果使用命令行參數進行調用,則會重命名這些參數;如果在沒有命令行參數的情況下調用(除了正則表達式),它會讀取標準輸入,在換行符上分割並將其作爲文件進行處理。我的版本粗心大意地淹沒整個標準輸入;如果處理千兆字節的文件名,這是次優的。 –