Bash
使用重命名遞歸替換文件名而不是目錄中的無效字元的腳本
我正在尋找一個腳本,它將查找並替換除
[^A-Za-z0-9._-]
特定文件類型(在本例中.avi
)以外的任何字元,並帶有下劃線_
。我希望它從目前路徑遞歸執行。我正在使用 Ubuntu。我不想或不需要更改任何文件夾名稱,因為我在創建時可以控制這些名稱。參考以下連結後,這是我現在所擁有的:
find . -depth -exec rename 's!([^/]*\Z)/[^A-Za-z0-9._-]/_/g' *.avi {} +
我顯然錯過了一些東西。請幫忙。:)
為什麼你的程式碼不起作用
萬用字元模式
*.avi
由執行find
前的shell擴展find
,所以它的效果取決於*.avi
目前目錄中是否有文件。有關更多解釋,請參閱find not recursive when file at top。要*.avi
在子目錄中展開,您需要做三件不同的事情:引用模式以使原始 shell 不會展開它;安排在每個子目錄中執行一個額外的 shell 來執行萬用字元擴展;並僅使用find
命令而不是任何文件類型查找目錄。此外,您的程式碼最終會呼叫
rename
目前目錄下任何級別的每個文件,包括子目錄本身,通過{} +
. 所以rename
對目錄進行操作,而不僅僅是正常文件。此外,您的 Perl 程式碼中存在語法錯誤。
使用 zsh 的工作解決方案
autoload -Uz zmv # best in ~/.zshrc zmv -n '(**/)(*.avi)(#qD^/)' '$1${2//[^a-zA-Z0-9._-]/_}'
^/
是選擇目錄以外的任何類型的文件。替換為僅.
用於正常文件。-n
用於空執行。高興時刪除。
find
與和的工作解決方案rename
使用基於 perl 的變體
rename
和find
支持的實現-execdir
:LC_ALL=C find . -depth -name '*[!a-zA-Z0-9._-]*.avi' ! -type d -execdir \ rename 's/[^a-zA-Z0-9._-]/_/g' {} +
不過,這種方法有一些注意事項:
- 每個包含要重命名的文件的目錄至少執行一個
rename
實例(rename
每個文件一個,其中一些find
實現/版本-execdir ... {} +
實際上與-execdir ... {} \;
. 相同(每個文件zmv
執行一個mv
,但您可以使用mv
內置功能zmodload zsh/files
加快速度)。- 使用
-execdir
,在包含這些文件的目錄find
中執行命令,並將相對於該目錄的路徑傳遞給命令。一些實現(GNU 實現)為文件添加前綴,有些則沒有。do的某些變體在 perl 表達式之後接受選項,這意味著如果您有一個名稱以 開頭的文件,則可能會導致問題。find``./``rename``-
- 即使文件名包含字節序列,否則我們必須使用
LC_ALL=C
for才能在語言環境中形成有效字元。繼承了這一點,並且無論如何在大多數變體中只適用於 ASCII。然而,這意味著它將用字元的字節數替換多字節字元。例如,它會將 UTF-8 重命名為而不是. 沒問題,因為它將多字節字元和所有無法解碼為字元的字節都轉換為一個字元。-name``rename``_``stéphane``st__phane``st_phane``zsh``_
- 與
zsh
‘s不同,在開始重命名之前zmv
,它不會執行完整性檢查(例如 2 個文件不會最終具有相同的名稱a+b.avi
和)。但是不應覆蓋現有文件。a@b.avi``rename