使用所有類型的字元重命名大量文件,具有 POSIX 可移植性
有時我需要重命名一個目錄中的所有文件(稍後將遵循重命名約定),其中文件名始終採用“filenamename.extension”的形式(副檔名始終存在並且會有所不同)。名稱可能包含空格和字元
$$ :graph: $$班級。我的第一個問題是它應該在 *NIX 系統(尤其是 Linux、BSD,後來的其他系統,比如 AIX)之間絕對可移植。我的第二個問題是$$ :graph: $$班級。文件名可以是:
cat.txt dog_and_cat.txt Where is the cat?.png my.cat.is.cute.txt.js.html ;;; ;;; ;;;.......321 áéúő _[a lot of whitespaces]_ óü^^^^^ö.jpg
很容易看出,這些很難處理並放入 for 循環中。例如,
for i in *; do something; done
並不總是喜歡空格和奇怪的字元,尤其是在不同的作業系統中。
重命名約定是將所有文件重命名為某種散列
$FOOBAR.$EXTENSION
形式,例如 md5sum。$FOOBAR
所以在for循環中我有一條線就像mv $FILE $(md5sum $FILE | sed 's/\ \ .\+//');
它會將文件移動到自身的 md5sum 中,但副檔名消失了。我想保留幾乎總是在
.[a-zA-Z0-9]{1,3}
表單中的擴展。有時.tar.gz
也需要保留一些副檔名(當然我可以將它們添加到變數中,比如MYEXTENSIONS='tar.gz tar.bz2 foo.bar'
)。我的直覺告訴我,這個問題可以通過參數化的預設 UNIX/shell 命令解決,但現在對我來說非常困難。我相信我會從答案中學到很多東西。我知道我說過神奇的詞portability,但如果我必須指定語言,則首選 bash 中的解決方案。
實際上,
for i in *; do something; done
正確處理每個文件名,除了以 a 開頭的文件名.
被排除在萬用字元匹配之外。要可移植地匹配所有文件(.
和除外),請匹配並跳過由於不匹配模式保持不變而導致的任何不存在的文件。..``* .[!.]* ..?*
如果您遇到問題,可能是因為您後來沒有
$i
正確引用。**始終在變數替換和命令替換: 周圍加上雙引號"$foo"
,"$(cmd)"
**除非您打算進行欄位拆分和通配。如果您需要將文件名傳遞給外部命令(此處不需要),請注意
echo "$foo"
不要總是按$foo
字面意思列印。少數 shell 執行反斜杠擴展,並且以$foo
開頭的少數值-
將被視為一個選項。準確列印字元串的安全且符合 POSIX 的方法是printf '%s' "$foo"
或
printf '%s\n' "$foo"
在末尾添加換行符。需要注意的另一件事是命令替換刪除了尾隨的換行符。如果您需要保留換行符,一個可能的技巧是將非換行符附加到數據中,確保轉換保留此字元,最後截斷此字元。例如:mangled_file_name="$(printf '%sa' "$file_name" | tr -sc '[:alnum:]-+_.' '[_*]')" mangled_file_name="${mangled_file_name%a}"
要提取文件的 md5sum,請避免在
md5sum
輸出中包含文件名,因為這會使其難以剝離。md5sum
在的標準輸入上傳遞數據。請注意,該
md5sum
命令不在 POSIX 中。一些 unix 變體有md5
或根本沒有。cksum
是 POSIX 但容易發生衝突。有關如何獲取文件副檔名的資訊,請參閱抓取文件名中的副檔名。
讓我們把它們放在一起(未經測試)。這裡的一切都可以在任何 POSIX shell 下工作;您可以從 bash 功能中獲得一點,但不多。
for old_name in * .[!.]* ..?*; do if ! [ -e "$old_name" ]; then continue; fi hash=$(md5sum <"$old_name") case "$old_name" in *.*.gz|*.*.bz2) # double extension ext=".${old_name##*.}" tmp="${old_name%.*}" ext=".${old_name##*.}$ext";; ?*.*) ext=".${old_name##*.}";; # simple extension *) ext=;; # no extension esac mv -- "$old_name" "$hash$ext" done
請注意,我沒有考慮已經存在指定名稱的目標文件的情況。特別是,如果您有現有文件的名稱看起來像您採用的約定,但校驗和部分與文件的內容不匹配,而是與具有相同副檔名的其他文件匹配,那麼會發生什麼將取決於相對詞典順序文件名。