Shell-Script
怎麼可能除了隱藏的’。來自重命名它們的腳本的文件和目錄?
我有一個腳本可以重命名,去掉空格、每個目錄和文件。它遞歸地執行它:
#!/bin/bash find -name "* *" -print0 | sort -rz | \ while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done
當我在我的
~
目錄中執行它時,腳本造成了一些意外的破壞,重命名了以下項目:
./.cache/google-chrome/Default/Storage/ext/nmmhkkegccagdldgiimedpiccmgmieda/def/Code Cache
./.cache/google-chrome/Default/Storage/ext/gfdkimpbcpahaombhbimeihdjnejgicl/def/Code Cache
./.cache/google-chrome/Default/Code Cache
我希望我的腳本除了以
.
重命名它開頭的任何目錄或文件。你會怎麼寫這樣的劇本?是否需要為此目的使用正則表達式?
只需使用
zsh
’szmv
:#! /bin/zsh - autoload -Uz zmv zmv '(**/)(* *)' '$1${2// /_}'
zmv
預設情況下跳過隱藏文件和隱藏目錄中的文件(除非您將(#qD)
限定符傳遞給第一個參數),- 它首先處理文件深度(
sort -rz
不保證您可以為此工作並且-prune
不兼容-depth
)- 我們不需要呼叫
dirname
/basename
(如果有一些文件名以換行符結尾,這將很昂貴並且不能與命令替換一起正常工作)。- 它沒有不匹配任意字節序列的問題
find
。*
- 如果有一些衝突(比如同時存在 a
a b c
和a_b c
files 都將重命名為a_b_c
),它將在開始時檢測到它並在進行任何重命名之前中止。要使用 GNU 工具做一些事情,那就是:
#! /bin/bash - export LC_ALL=C while IFS= read <&3 -rd '' file; do dir=${file%/*} name=${file##*/} mv -i -- "$file" "$dir/${name// /_}" done 3< <( find . -name '.?*' -prune -o -name '* *' -print0 | tac -s '')
這裡,
- 將語言環境設置為與任何字節序列匹配,
C
而*
不僅僅是在使用者語言環境中形成有效字元的字節。請注意,消息(錯誤、提示…)隨後將以英語而不是使用者的語言發出。- 傳遞
-i
tomv
以防止無意中破壞文件。- 通過 fd 3 而不是 stdin 傳遞文件列表,因此
mv -i
提示有效。- 使用
tac -s ''
而不是sort -rz
反轉輸出以確保葉子在它們所在的分支之前被重命名。- 用標準和參數擴展運算符替換
dirname
/ 。basename``${var##pattern}``${var%pattern}
- 還傳遞
-r
toread
以禁用其對反斜杠的特殊處理。- 確保 for
read
$IFS
為空,因此它不會從輸入記錄中刪除尾隨空格。
無需過多查看管道中的其他命令,您
find
可以避免輸入任何具有隱藏名稱的目錄:find . ! -path . -name '.*' -prune -o -name '* *' -print0 | ...
這將從搜尋樹中刪除
.
名稱開頭的所有目錄,但.
目錄(目前目錄)除外。它也將不再找到隱藏的名稱。在查看了您的其餘程式碼後,我建議您改用
rename
(Perl 變體):find . ! -path . -name '.*' -prune \ -o -type f -name '* *' -execdir rename -n -v 'tr/ /_/' {} \;
這將搜尋包含空格的文件名,然後用下劃線替換其中的所有空格,同時忽略隱藏名稱並且不輸入隱藏目錄。
rename
呼叫該實用程序-n
以阻止它實際執行任何操作(這是“試執行”)。-n
當您確信它在做正確的事情時刪除。沒有
rename
,你會做類似的事情find . ! -path . -name '.*' -prune \ -o -type f -name '* *' -exec bash -c ' for pathname do filename=${pathname##*/} echo mv "$pathname" "${pathname%/*}/${filename// /_}" done' bash {} +
也就是說,呼叫一個
bash
遍歷找到的名稱的內聯腳本,通過將空格更改為下劃線來重命名每個名稱。
echo
當您確信這樣做是正確的時,請刪除。