ファイル名に非ASCII文字または非印刷文字が含まれるファイルを識別する


24

約700,000個のファイルがある80GBのディレクトリサイズでは、ファイル名に英語以外の文字が含まれるファイル名がいくつかあります。苦労してファイルリストをトロールする以外に、次のものがあります。

  • これらのファイル名をリストするか、そうでなければ識別するための簡単な方法は?
  • 印刷可能な英語以外の言語の文字を生成する方法-印刷可能な範囲にリストされていない文字man ascii(したがって、これらのファイルが識別されていることをテストできます)

回答:


32

「外部」が「ASCII文字ではない」ことを意味すると仮定するfindと、パターンで使用して、名前に印刷可能なASCII文字を持たないすべてのファイルを見つけることができます。

LC_ALL=C find . -name '*[! -~]*'

(スペースはhttp://www.asciitable.com/にリストされている最初の印刷可能文字で~あり、最後の文字です。)

のヒントLC_ALL=Cが必要です(実際、LC_CTYPE=CおよびLC_COLLATE=C)、そうでない場合、文字範囲は誤って解釈されます。マニュアルページも参照してくださいglob(7)。以来LC_ALL=C原因はfindASCII文字列として解釈し、それが(のようなマルチバイト文字を出力しますπ疑問符として)。これを修正するには、いくつかのプログラム(例:)にパイプするかcat、ファイルにリダイレクトします。

文字範囲を指定する代わりに、[:print:]「印刷可能な文字」を選択するためにも使用できます。必ずCロケールを設定してください。そうしないと、かなり(一見)任意の動作が得られます。

例:

$ touch $(printf '\u03c0') "$(printf 'x\ty')"
$ ls -F
dir/  foo  foo.c  xrestop-0.4/  xrestop-0.4.tar.gz  π
$ find -name '*[! -~]*'       # this is broken (LC_COLLATE=en_US.UTF-8)
./x?y
./dir
./π
... (a lot more)
./foo.c
$ LC_ALL=C find . -name '*[! -~]*'
./x?y
./??
$ LC_ALL=C find . -name '*[! -~]*' | cat
./x y
./π
$ LC_ALL=C find . -name '*[![:print:]]*' | cat
./x y
./π

1
UTF-8またはASCIIと互換性のない外部文字セットを使用しているファイル名があることに注意してください。これらの場合、文字の代わりに疑問符が表示される場合があります。
Lekensteyn

1
+1ですが、LC_COLLATEを設定せずにCに設定し、LC_ALL変数が環境にある場合でも動作することを確認することはあまり意味がないため、LC_ALL=C代わりに使用します。LC_COLLATE=CLC_CTYPE
ステファンシャゼル14年

場合SPC印刷可能な、そして何についてTABとをLF、典型的には、テキストファイルで発見されましたか?
ステファンシャゼル14年

1
感謝-これにより、長いハイフン、短いハイフン、および単一引用符のバリアントを持つ6つのファイルが見つかりました。これらはすべてMS Wordに由来していました。LC_ALLとLC_COLLATEの間にリストされたファイルに違いはありません。LC_COLLATEは非ASCII文字を正しく表示しましたが、LC_ALLは表示されました??? 代わりに。素晴らしい答えです!
容疑者14年

1
@suspectusステファンからの提案に基づいた回答で更新しました。以下のためにLC_COLLATELC_CTYPE、また参照のfind(1)manページを。
Lekensteyn

6

を使用して各ファイル名を翻訳tr -d '[\200-\377]'し、元の名前と比較する場合、特殊文字を含むファイル名は同じではありません。

(上記は、外国語で非ASCIIを意味すると仮定しています)


2
それはまた、削除[]ほとんどでtr実装。
ステファンシャゼル14年

はい-それは削除をしました[し、]私のシステムで。
容疑者14年

+1-ソリューションは、([および]s に加えて)非ASCIIシンボルを持つすべての(6つの)ファイル名を見つけました。ありがとう。
容疑者14年

3

を使用trして、ファイル名から任意の外部文字を削除し、結果を元のファイル名と比較して、外部文字が含まれているかどうかを確認できます。

find . -type f > filenames
while read filename; do
      stripped="$(printf '%s\n' "$filename" | tr -d -C '[[:alnum:]][[:space:]][[:punct:]]')"
      test "$filename" = "$stripped" || printf '%s\n' "$filename"; 
done < filenames

4
それは私の答えに素敵な拡張機能ですが、それはあまりにも単純である、ファイル名には、それらの中に改行を持つことができ、その後、あなたのスクリプトは動作しません
ティモ

1
find出力を後処理する場合は、この回答に示すように、NULで終了する出力/入力を使用します
レーケンシュタイン14年

0

受け入れられた答えは役に立ちますが、ファイル名が既にLANG/ LC_CTYPEで指定されたエンコーディングにある場合は、次のようにするだけの方が良いでしょう:

LC_COLLATE=C find . -name '*[! -~]*'

文字クラスはの影響を受けますLC_CTYPEが、上記のコマンドは文字クラスを使用せず、範囲のみを使用するためLC_CTYPE、異常な文字が疑問符に置き換えられないようにします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.