grep
この仕事には不適切なツールです。
� U+FFFD REPLACEMENT CHARACTER
が表示されます 文字通りファイルの内容に含まれているからではなく、テキストベースの入力のみを処理するはずのツールでバイナリ ファイルを調べたからです。無効な入力 (つまり、ランダムなバイナリ データ) を処理する標準的な方法は、現在のロケール (ほとんどの場合 UTF-8) で無効なすべてのものを、画面に表示される前に U+FFFD に置き換えることです。
つまり、リテラル \xEF\xBF\xBD
の可能性が非常に高いことを意味します (U+FFFD 文字の UTF-8 バイト シーケンス) はファイル内で発生しません。 grep
あなたに言うのは完全に正しいです、何もありません.
ファイルに不明なバイナリが含まれているかどうかを検出する 1 つの方法は、file(1)
を使用することです。 コマンド:
$ head -c 100 /dev/urandom > rubbish.bin
$ file rubbish.bin
rubbish.bin: data
不明なファイル タイプの場合は、単に data
と表示されます .試す
$ file out.txt | grep '^out.txt: data$'
ファイルに実際に任意のバイナリが含まれているかどうかを確認するため、おそらくゴミです。
out.txt
であることを確認したい場合 は UTF-8 でエンコードされたテキスト ファイルのみです。代わりに iconv
を使用できます :
$ iconv -f utf-8 -t utf-16 out.txt >/dev/null
TL;DR:
grep -axv '.*' out.txt
長い答え
現在の両方の回答は、非常に誤解を招きやすく、基本的に間違っています。
テストするには、次の 2 つのファイルを入手します (非常に評価の高い開発者:Markus Kuhn から):
$ wget https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-demo.txt
$ wget https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
デモ
最初の UTF-8-demo.txt
は、UTF-8 が多くの言語、数学、点字、その他多くの有用な種類の文字をどれだけうまく表示できるかを示すために設計されたファイルです。テキスト エディタ (utf-8 を理解するもの) で見てみると、多くの例が表示されますが、いいえ は表示されません。 �
.
1 つの回答が提案するテスト:文字範囲を \x00-\x7F
に制限する このファイル内のほとんどすべてを拒否します。
それは非常に間違っており、�
は削除されません。 そのファイルには何もないので .
その回答で推奨されているテストを使用すると、 72.5 %
が削除されます ファイルの:
$ grep -oP "[^\x00-\x7F]" UTF-8-demo.txt | tr -d '\n' | wc -c
10192
$ cat UTF-8-demo.txt | wc -c
14058
これは (ほとんどの実用的な目的では) ファイル全体です。完全に有効な文字を表示するように非常によく設計されたファイル。
テスト
2 番目のファイルは、いくつかの境界ケースを試して、utf-8 リーダーが適切に機能していることを確認するように設計されています。 「�」が表示される原因となる多くの文字が内部に含まれています。しかし、 file
を使用する他の回答の推奨事項 (選択されたもの) このファイルではひどく失敗します。ゼロバイトのみを削除する (\0
) (技術的には有効な ASCII) と \x7f
バイト (DEL - 削除) (明らかに ASCII 文字でもあります) は all を作成します file
に有効なファイル コマンド:
$ cat UTF-8-test.txt | tr -d '\0\177' > a.txt
$ file a.txt
a.txt: Non-ISO extended-ASCII text, with LF, NEL line terminators
file
だけではありません 多くのを検出できません 不正な文字であるだけでなく、UTF-8 でエンコードされたファイルであることを検出して報告することもできません。
はい、file
UTF-8 でエンコードされたテキストを検出して報告できます:
$ echo "ééakjfhhjhfakjfhfhaéá" | file -
/dev/stdin: UTF-8 Unicode text
また、file
1 から 31 の範囲のほとんどの制御文字を ASCII として報告できません。それ (file
) は、一部の範囲を data
として報告します :
$ printf '%b' "$(printf '\\U%x' {1..6})" | file -
/dev/stdin: data
その他 ASCII text
:
$ printf '%b' "$(printf '\\U%x' 7 {9..12})" | file -
/dev/stdin: ASCII text
印刷可能な文字範囲 (改行あり):
$ printf '%b' "$(printf '\\U%x' {32..126} 10)" | file -
/dev/stdin: ASCII text
ただし、範囲によっては奇妙な結果になる場合があります:
$ printf '%b' "$(printf '\\U%x' {14..26})" | file -
/dev/stdin: Atari MSA archive data, 4113 sectors per track, starting track: 5141, ending track: 5655
プログラム file
テキストを検出するためのツールではなく、魔法を検出するためのツールです 実行可能プログラムまたはファイル内の番号。
範囲 file
検出し、私が報告した対応するタイプは次のとおりです:
-
1 バイト値、ほとんどが ASCII:
{1..6} {14..26} {28..31} 127 :data {128..132} {134..159} :Non-ISO extended-ASCII text 133 :ASCII text, with LF, NEL line terminators 27 :ASCII text, with escape sequences 13 :ASCII text, with CR, LF line terminators 8 :ASCII text, with overstriking 7 {9..12} {32..126} :ASCII text {160..255} :ISO-8859 text
-
Utf-8 でエンコードされた範囲:
{1..6} {14..26} {28..31} 127 :data 27 :ASCII text, with escape sequences 13 :ASCII text, with CR, LF line terminators 8 :ASCII text, with overstriking 7 {9..12} {32..126} :ASCII text {128..132} {134..159} :UTF-8 Unicode text 133 :UTF-8 Unicode text, with LF, NEL line terminators {160..255} :UTF-8 Unicode text {256..5120} :UTF-8 Unicode text
考えられる解決策の 1 つを以下に示します。
前の回答
投稿する文字の Unicode 値は次のとおりです:
$ printf '%x\n' "'�"
fffd
はい、それは Unicode 文字 '置換文字' (U+FFFD) です。これは、無効を置き換えるために使用される文字です テキストで見つかった Unicode 文字。これは「視覚補助」であり、実際のキャラクターではありません。無効な UNICODE を含むすべての行を検索して一覧表示するには 文字の使用:
grep -axv '.*' out.txt
ただし、無効な文字があるかどうかのみを検出したい場合は、次を使用します:
grep -qaxv '.*' out.txt; echo $?
結果が 1
の場合 ファイルはクリーンです。それ以外の場合はゼロになります 0
.
�
を見つける方法 文字の場合は、これを使用してください:
➤ a='Basically, if the file "out.txt" contains "�" anywhere in the file I'
➤ echo "$a" | grep -oP $(printf %b \\Ufffd)
�
または、システムが UTF-8 テキストを正しく処理する場合は、単に:
➤ echo "$a" | grep -oP '�'
�
この非常に初期の回答は、次の元の投稿に対するものでした:
<ブロック引用>bash スクリプトで Unicode を grep する方法
if grep -q "�" out.txt
then
echo "working"
else
cat out.txt fi
基本的に、ファイル「out.txt」にファイルのどこかに「�」が含まれている場合、「作業中」とエコーしたいのですが、ファイル「out.txt」にファイルのどこにも「�」が含まれていない場合は、好きですcat out.txt へ
試してみてください
grep -oP "[^\x00-\x7F]"
if .. then
で 次のようなステートメント:
if grep -oP "[^\x00-\x7F]" file.txt; then
echo "grep found something ..."
else
echo "Nothing found!"
fi
説明:
-P
、--perl-regexp
:PATTERN は Perl の正規表現です-o
、--only-matching
:PATTERN に一致する行の一部のみを表示[^\x00-\x7F]
単一の非 ASCII 文字に一致する正規表現です。[[:ascii:]]
- 単一の ASCII 文字に一致[^[:ascii:]]
- 単一の非 ASCII 文字に一致
bash
で
LC_COLLATE=C grep -o '[^ -~]' file