一般的に、ファイル名の文字化けは、convmv コマンドを利用して解決します。
convmv -f sjis -t utf8 --notest *
convmv コマンドを同じファイルに対して二度実行してしまうと危険です。上の例では、 UTF-8 なファイル名を ShiftJIS として扱い、さらに UTF-8 としてリネームしようとするのだから、ぐちゃぐちゃに壊れてしまいます。また、To と From のオプションを間違ってしまい、文字化けしたファイル名になる事もあります。
このようなミスを犯した場合、To と From の文字コードを逆にして再変換すれば理論的に元に戻るハズだが、”ミスを犯した事に気付いたのが数日後”とか、”再変換しようと思ったら突然家が爆発して、それどころじゃなくなった”など、再変換を行なっていない状況から復旧させねばならない事もあるでしょう。
さらに、文字コードはそれぞれの文字が必ずしも一対一で関連付けされている訳でもないので、convmv を使っての変換とは言うものの、完全な可逆変換ではありません。
そのような残念な状況になってしまいました。nkf には入力したデータの文字コードを調べる -g オプションでみたところ、
ls -a | nkf -g
BINARY
と表示されました。ちゃんとした文字コードであれば、UTF-8 や ASCII といった答えが返ってくる。バイナリ、つまり壊れたファイル名という答えでした。ファイル名が正しくないと、シェル上で取り扱うには厄介で、シェル展開で表現されるファイル名による指定(*など)がことごとく失敗してしまいます。これではリネームも出来ません。
ファイルを特定する事が出来れば、後はどうにかなりそうな予感がしたので、ファイル名の他に唯一ファイルを特定する要素、i ノード番号に着目しました。幸い、i ノード番号を得る方法と、それを引数にとってファイルを指定する方法がある。以下のようなスクリプトを書きました。
#!/bin/sh
# fixfname.sh
dir=$1
for inum in <code>ls -ai $dir | awk '{print $1}'</code>;
do
find $dir -inum $inum -ok mv '{}' $dir/$inum.fix \;
done
ls コマンドの -i オプションでファイル名と共に i ノード番号を表示します。その i ノード番号を find コマンドで利用して、新しい名前を与える、といった形です。次のように使います。
sh fixfname.sh TargetDirectory
find に -ok オプションを付けているので、確認しながらファイル名を変更する事になります。めちゃくちゃだったファイル名は、”16785735.fix” のような i ノード番号 + .fix といった形式に置き替えられます。あとは、fileコマンドやmimetypeコマンドで正しい拡張子を拡張子を調べてリネームしてあげればいいでしょう。
※ 2020/07/02 度重なるブログ移転・ブログシステムのアップデートにより崩れた記事を校正。