Command-Line

如何讓這個查找和重命名命令與子目錄一起使用?

  • August 27, 2012

可能重複:

遞歸重命名文件和目錄

我有一個很大的音樂文件目錄,隨著文件和目錄的來來去去,這些文件經常發生變化。我的偏好是確保文件和目錄名稱中沒有空格,因此我將它們全部替換為下劃線。

我進入主目錄並執行以下命令:

$ find -type d -exec rename 'y/\ /\_/' {} \;

問題是當有子目錄時,這個命令似乎會失去並且會返回錯誤。所以如果我有以下目錄結構:

在此處輸入圖像描述

…如果我執行命令,我會收到以下錯誤:

$ find -type d -exec rename 'y/\ /\_/' {} \;
find: `./Test 02': No such file or directory
find: `./Test 01': No such file or directory
find: `./Test 03': No such file or directory

然後結果是我的目錄結構看起來像這樣。請注意,子目錄中仍然有空格:

在此處輸入圖像描述

如果我再次執行該命令,我會收到這些錯誤,即使它似乎重命名了相關目錄:

$ find -type d -exec rename 'y/\ /\_/' {} \;
find: `./Test_01/Test A': No such file or directory
find: `./Test_01/Test C': No such file or directory
find: `./Test_01/Test B': No such file or directory

最後,我再次執行該命令,沒有收到任何錯誤,並且所有目錄和子目錄都按我想要的方式命名:

在此處輸入圖像描述

顯然,當我有多個子目錄時,這需要執行命令更多次,這可能會變得乏味。

我怎樣才能使這個命令只需要執行一次,它會一次性重命名所有目錄和子目錄?

我的最終目標是將它包含在 Bash 腳本中,以便我可以將它與其他類似的管家命令一起執行,因此我需要它不返回錯誤或需要我提供更多輸入。另外,如果這有所不同,我正在執行 Ubuntu 12.04。

這是發生的事情:

  • find找到匹配的目錄./Test 02
  • find在該目錄上執行rename命令。
  • rename重命名Test 02Test_02.
  • find試圖進入目錄Test 02。但它不再存在。

解決此問題的最簡單方法是告訴find以相反的方式工作:首先在目錄中查找匹配項,然後檢查目錄本身是否匹配。這就是-depth選項的作用。

如果你只添加-depth,你會遇到另一個問題,那就是當find到達時Test 01/Test A,它會呼叫rename 'y/\ /\_/' 'Test 01/Test A',它會嘗試將該目錄重命名為Test_01/Test_A. 這將失敗,因為沒有名為Test_01. 一個簡單的解決方法是使用該-execdir選項,該選項rename在目錄內部呼叫並作為參數Test 01傳遞。您可以通過在一批中Test A傳遞多個參數來加快速度,使用而不是終止命令。rename``+``;``-execdir

find -depth -name '* *' -type d -execdir rename 'y/ /_/' {} +

或者,使用這個簡短但神秘的 zsh 命令:

autoload zmv
zmv -Qw '**/*(/D)' '$1${2// /_}'

zmv函式根據模式重命名文件。源模式是,它以遞歸方式**/*匹配所有子目錄中的所有文件 ( ) ( )。glob 限定符(由選項啟動)表示僅匹配目錄 ( ) 並且包含點文件 ( )。該選項為源模式中的每個萬用字元創建一個反向引用。替換以which 指定第一個萬用字元的匹配開始(對於,這包括一個 final ),然後是,它(匹配的內容)被修改為用 替換所有空格字元。添加*``**/``-Q``/``D``-w``$1``**``/``${2// /_}``$2``*``_``-v選項來查看命令的作用,您會注意到它首先遍歷深度,例如find -depth.

引用自:https://unix.stackexchange.com/questions/46344