Shell

使用特殊字元批量重命名(或正確顯示)文件

  • April 5, 2019

我有一堆目錄和子目錄,其中包含帶有特殊字元的文件,比如這個文件:

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'

但是我找不到可以滿足我所有需求的解決方案:

  1. 辨識所有具有不可顯示字元的文件(上面忽略了太多)
  2. 對於目錄樹中的所有這些文件(遞歸),執行 mv oldname newname
  3. (可選)將特殊字元(例如 ä)音譯為 a 的能力(不是必需的,但會很棒)

要麼

  1. 正確顯示所有這些文件(嘗試打開它們時應用程序中沒有錯誤)

我有一些零碎的東西,比如遍歷所有文件並移動它們,但是辨識文件並為 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

您可以使用recodeiconv檢查它們在另一個語言環境中是否更有意義:

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來顯示它會做什麼,而無需實際重命名文件。

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