使用特殊字元批量重命名(或正確顯示)文件
我有一堆目錄和子目錄,其中包含帶有特殊字元的文件,比如這個文件:
robbie@phil:~$ ls test�sktest.txt test?sktest.txt
Find 揭示了一個轉義序列:
robbie@phil:~$ find test�sktest.txt -ls 424512 4000 -rwxr--r-x 1 robbie robbie 4091743 Jan 26 00:34 test\323sktest.txt
我什至可以在控制台上輸入他們的名字的唯一原因是製表符完成。這也意味著我可以手動重命名它們(並去除特殊字元)。
我已將 LC_ALL 設置為 UTF-8,這似乎沒有幫助(也不是在新外殼上):
robbie@phil:~$ echo $LC_ALL en_US.UTF-8
我正在使用我的 mac 上的 ssh 連接到機器。這是一個 Ubuntu 安裝:
robbie@phil:~$ cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=7.10 DISTRIB_CODENAME=gutsy DISTRIB_DESCRIPTION="Ubuntu 7.10"
Shell 是 Bash,TERM 設置為 xterm-color。
這些文件已經存在了很長一段時間,並且它們不是使用安裝的 Ubuntu 創建的。所以我不知道以前的系統編碼設置是什麼。
我已經嘗試過以下方式:
find . -type f -ls | sed 's/[^a-zA-Z0-9]//g'
但是我找不到可以滿足我所有需求的解決方案:
- 辨識所有具有不可顯示字元的文件(上面忽略了太多)
- 對於目錄樹中的所有這些文件(遞歸),執行 mv oldname newname
- (可選)將特殊字元(例如 ä)音譯為 a 的能力(不是必需的,但會很棒)
要麼
- 正確顯示所有這些文件(嘗試打開它們時應用程序中沒有錯誤)
我有一些零碎的東西,比如遍歷所有文件並移動它們,但是辨識文件並為 mv 命令正確格式化它們似乎是困難的部分。
任何關於它們為什麼不能正確顯示或如何“猜測”正確編碼的額外資訊也是受歡迎的。(我試過 convmv 但它似乎並沒有完全符合我的要求:http: //j3e.de/linux/convmv/)
我猜您會看到這個
�
無效字元,因為該名稱包含一個無效的 UTF-8 字節序列。典型的 unix 文件系統(包括您的文件系統)上的文件名是字節字元串,由應用程序決定使用什麼編碼。如今,有一種使用 UTF-8 的趨勢,但它並不是通用的,尤其是在那些永遠無法使用純 ASCII 並且在 UTF-8 甚至還沒有出現之前就一直在使用其他編碼的語言環境中。嘗試
LC_CTYPE=en_US.iso88591 ls
查看文件名在 ISO-8859-1 (latin-1) 中是否有意義。如果沒有,請嘗試其他語言環境。請注意,LC_CTYPE
這裡只有區域設置很重要。在 UTF-8 語言環境中,以下命令將顯示名稱不是有效 UTF-8 的所有文件:
grep-invalid-utf8 () { perl -l -ne '/^([\000-\177]|[\300-\337][\200-\277]|[\340-\357][\200-\277]{2}|[\360-\367][\200-\277]{3}|[\370-\373][\200-\277]{4}|[\374-\375][\200-\277]{5})*$/ or print' } find | grep-invalid-utf8
您可以使用recode或iconv檢查它們在另一個語言環境中是否更有意義:
find | grep-invalid-utf8 | recode latin1..utf8 find | grep-invalid-utf8 | iconv -f latin1 -t utf8
一旦您確定一堆文件名採用某種編碼(例如 latin1),重命名它們的一種方法是
find | grep-invalid-utf8 | rename 'BEGIN {binmode STDIN, ":encoding(latin1)"; use Encode;} $_=encode("utf8", $_)'
這使用了Debian 和 Ubuntu 上可用的 perl rename命令。您可以通過它
-n
來顯示它會做什麼,而無需實際重命名文件。