GNU/Linux >> Linux の 問題 >  >> Linux

bash スクリプトで unicode を grep する方法

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

Linux
  1. Bashスクリプトをファイルに接続できますか?

  2. シェルスクリプトBashでサブストリングをチェックする方法は?

  3. Bashスクリプトで文字列を分割する方法

  1. ファイル内の複数行パターンを検索するにはどうすればよいですか?

  2. Bash スクリプトのスクリプト ファイル名を知るにはどうすればよいですか?

  3. VimでBashスクリプトを強調表示するには?

  1. bash スクリプトを使用してファイル名のスペースを置き換える方法

  2. BashでCSVファイルを解析するには?

  3. 連続ストリームを「grep」する方法は?