ASCII以外のすべての文字をgrepするにはどうすればよいですか?


359

非常に大きなXMLファイルがいくつかあり、ASCII以外の文字を含む行を見つけようとしています。私は以下を試しました:

grep -e "[\x{00FF}-\x{FFFF}]" file.xml

ただし、指定した範囲の文字が含まれているかどうかに関係なく、ファイルのすべての行が返されます。

構文が間違っているのですか、それとも他の何か間違っているのですか?私も試しました:

egrep "[\x{00FF}-\x{FFFF}]" file.xml 

(パターンを一重引用符と二重引用符で囲みます)。


ASCII文字は1バイトのみなので、ファイルがユニコードでない限り、0xFFを超える文字はありません。
zdav

どのようにして\ xFFを超えますか?Grepは「grep:範囲が文字クラスで順不同」エラーを出します。
Mudit Jain、2014

回答:


494

次のコマンドを使用できます。

grep --color='auto' -P -n "[\x80-\xFF]" file.xml

これにより、行番号が表示され、非ASCII文字が赤で強調表示されます。

一部のシステムでは、設定によっては上記が機能しないため、逆でgrepできます

grep --color='auto' -P -n "[^\x00-\x7F]" file.xml

また、重要なビットは:に-P相当するフラグである--perl-regexpため、パターンをPerl正規表現として解釈します。それはまた言う

これは非常に実験的なものであり、grep -Pは実装されていない機能を警告する場合があります。


42
これはgrepPオプションをサポートしていないため、BSD (OS X 10.8 Mountain Lion)では機能しません。
バスティアンM.ヴァンデウィアード2012年

20
私の最後のコメントを更新するために、GNUバージョンのgrepがHomebrewのdupesライブラリで利用可能です(を使用して有効化brew tap homebrew/dupes):brew install grep
バスティアンM.ファンデウィアード

48
@BastiaanVanDeWeerdは正しいです。DarwinがGNU grepではなくBSD grepを使用するようになったため、OSX 10.8のgrepはPCRE(「Perl互換の正規表現」)をサポートしなくなりました。インストールする代わりdupes、ライブラリをインストールすることですpcre代わりに:brew install pcre...その一環として、あなたが得るpcregrep次のように使用できるユーティリティを、:pcregrep --color='auto' -n "[\x80-\xFF]" file.xml
pvandenberk

15
Mac brewユーザーの場合、GNUのcoreutilsはを使用してインストールできますbrew install coreutils。これにより、 'g'が前に付いた多くのGNUツールが提供されますggrep。この場合は使用します。これにより、システム固有のMacスクリプトがBSD grepに依存するようになったため、システムユーティリティの置き換えによる問題を回避できます。
Joel Purra 2014年

22
これag "[\x80-\xFF]" fileは、インストールする必要があるMacで正常に機能しますthe_silver_searcher
slf 14

123

上記のソリューションのほとんどがそうであるように、非ASCII文字のバイト範囲についての仮定を行う代わりに、代わりにASCII文字の実際のバイト範囲について明示する方がIMOがわずかに優れています。

たとえば、最初のソリューションは次のようになります。

grep --color='auto' -P -n '[^\x00-\x7F]' file.xml

(基本的に、16進数のASCII範囲外の任意の文字を読み取る:\ x00から\ x7Fまで)

マウンテンライオンでは動作しません(BSD grepにはPCREサポートがないため)がpcreHomebrewを介してインストールされている場合、以下も同様に動作します。

pcregrep --color='auto' -n '[^\x00-\x7F]' file.xml

誰でも思いつくことができる長所と短所はありますか?


9
これは実際には、上記のソリューションが失敗した私にとってはうまくいきました。M $ Wordアポストロフィの検索は、これまでになく簡単になりました。
AlbertEngelB 2015

2
bash互換のシェルがあってもpcre-grepが機能しない場合はLC_COLLATE=C grep $'[^\1-\177]'機能します(nullバイトのないファイルの場合)
idupree

2
このソリューションは、上記のソリューションよりも一貫して機能するようです。
0xcaff 2015

1
私はこれを使用して、UTF8ファイルで漢字、キリル文字、および繁体字中国語をピックアップする必要がありました。「[\ x80- \ xFF]」を使用すると、これらすべてが見つかりませんでした。
buckaroo1177125 2015

1
他のオプションは素晴らしかったがそれほど優れていなかった一方で、プロはこれがうまく機能したことです。これまでに短所は見つかりませんでした。
jwpfox 2016

67

次は私のために働きます:

grep -P "[\x80-\xFF]" file.xml

非ASCII文字は0x80で始まり、バイトを見ると0xFFに行きます。Grep(およびそのファミリ)は、マルチバイト文字を単一のエンティティにマージして正規表現マッチングを行うためのUnicode処理を行いません。-P私のgrep のオプションで\xddは、文字クラスでエスケープを使用して、必要なことを実行できます。


1
複数のファイルでこれを呼び出す方法がすぐにわからない可能性があるビューの場合は、次のコマンドを実行します。find。-name * .xml | xargs grep -P "[\ x80- \ xFF]"
David Mohundro

1
これは一致を返しますが、文字が何で、どこにあるのかはわかりません。どのようにしてキャラクターが何で、どこにあるのかわかりますか?
Faheem Mitha、2011年

"-n"を追加すると、行番号が表示されます。さらに、非表示の文字がターミナルでブロックとして表示されます。grep -n -P "[\ x80- \ xFF]" file.xml
fooMonster

4
韓国語ハングルに問題がありecho '소녀시대' | grep -P "[\x80-\xFF]"ます。何も返されません。他の誰かが確認できますか?(GNU grep 2.21)
フラブジュ2015年

@frabjousここでも同じですが、逆がうまくいきます:echo '소녀시대' | grep -P "[^\x00-\x7F]"。またはthe_silver_searcher、@ slfで指摘されているとおりに使用する:echo '소녀시대' | ag "[\x80-\xFF]"
psmith

55

Perlで

perl -ane '{ if(m/[[:^ascii:]]/) { print  } }' fileName > newFile

1
OSX10.11では、実際に機能するこれを見つける前に、いくつかのgrep + regexソリューションを試さなければなりませんでした
sg

そのOSXソリューション@sgを共有することに注意してください!
地球理論

上記のperlスクリプトは私が話しているということなソリューションです
SG

5
perl -lne 'print if /[^[:ascii:]]/' file.xml
16

43

簡単な方法は、ASCII以外の文字をASCII文字ではない文字として定義することです。

LC_ALL=C grep '[^ -~]' file.xml

^必要に応じてタブを追加します。

設定するLC_COLLATE=Cことで、多くのロケールで文字範囲の意味についての厄介な驚きを回避できます。LC_CTYPE=Cシングルバイト文字を一致させるには設定が必要です—そうでない場合、コマンドは現在のエンコーディングの無効なバイトシーケンスを見逃します。設定によりLC_ALL=C、ロケールに依存する効果が完全に回避されます。


RedHat 6.4とtcshでは、<<< env LC_COLLATE = C grep -n '[^-〜]' file.xml >>>を使用する必要がありました。行番号を取得するために-nを追加しました。
ddevienne 2014

私にとってecho "A" | LC_COLLATE=C grep '[^ -~]'はマッチを返します
奇抜な

1
@frabjousがある場合LC_ALL=en_US.UTF-8、それはLC_COLLATE設定より優先されます。あなたはあなたの環境でこれを持ってはいけません!LC_ALL特定のタスクが特定のロケール、通常はを使用するように強制するだけCです。すべてのカテゴリのデフォルトロケールを設定するには、LANG
Gilles「SO-邪悪なことをやめよう」

1
最初はを追加しませんでしLC_ALL=Cた。MacOS XとUbuntuでは動作が異なります。この設定を追加すると、同じ結果が得られます。
Max Peng

1
これはMacで機能しますが、他のgrepベースのソリューションは機能しません。
マティアスフリップ

26

ここに私が見つけた別のバリアントがあります。これは、受け入れられた回答でのgrep検索の結果とはまったく異なる結果を生成[\x80-\xFF]ます。おそらく、ASCII以外の追加の文字を見つけることは誰かにとって役に立つでしょう:

grep --color='auto' -P -n "[^[:ascii:]]" myfile.txt

注:私のコンピューターのgrep(Mac)には-Pオプションがなかったので、brew install grep、上記の呼び出しをのggrep代わりにで開始しましたgrep


2
MacとLinuxの両方で機能するため、これは断然最良の答えです。
tommy.carstensen 2018年

Linuxで私のために働いた唯一のもの。

9

次のコードは機能します。

find /tmp | perl -ne 'print if /[^[:ascii:]]/'

/tmp検索するディレクトリの名前に置き換えます。


2
Macでは、これは機能しますが、grepベースの機能のほとんどは機能しません。
Matthias Fripp

9

印刷できない文字を検索しています。TLDR; エグゼクティブサマリー

  1. 制御文字と拡張ユニコードの検索
  2. ロケール設定など LC_ALL=C、grepが拡張Unicodeで期待することを実行するために必要

SO優先の非ASCII文字ファインダー:

$ perl -ne 'print "$. $_" if m/[\x00-\x08\x0E-\x1F\x80-\xFF]/' notes_unicode_emoji_test

上の答えのように、逆grep:

$ grep --color='auto' -P -n "[^\x00-\x7F]" notes_unicode_emoji_test

トップの回答と同じですが、WITH LC_ALL=C

$ LC_ALL=C grep --color='auto' -P -n "[\x80-\xFF]" notes_unicode_emoji_test

。。もっと 。。これについては耐え難いほどの詳細:。。

私はコメントの中に埋められた上記のHarveyに同意します。印刷不可能な文字を検索する方が多くの場合、または本当に印刷不可と考える必要があるときに非ASCIIと考えるのは簡単です。Harveyは「これを使用する:」を提案してい[^\n -~]ます。DOSテキストファイルに\ rを追加してください。これは「[^\x0A\x020-\x07E]」に、CRの場合は\ x0Dを追加します

また、-c(一致したパターンの数を表示)をgrepに追加すると、一致しない文字列が端末を混乱させる可能性があるため、印刷できない文字を検索するときに役立ちます。

範囲0-8と0x0e-0x1fを(0x80-0xffの範囲に)追加すると便利なパターンです。これには、TAB、CR、LF、および1つまたは2つ以上の一般的でない印刷可能な文字は含まれません。したがって、IMHOは非常に便利な(大雑把ではありますが)grepパターンです。

grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" *

実際には、一般的にこれを行う必要があります:

LC_ALL=C grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" *

壊す:

LC_ALL=C - set locale to C, otherwise many extended chars will not match (even though they look like they are encoded > 0x80)
\x00-\x08 - non-printable control chars 0 - 7 decimal
\x0E-\x1F - more non-printable control chars 14 - 31 decimal
\x80-1xFF - non-printable chars > 128 decimal
-c - print count of matching lines instead of lines
-P - perl style regexps

Instead of -c you may prefer to use -n (and optionally -b) or -l
-n, --line-number
-b, --byte-offset
-l, --files-with-matches

たとえば、findを使用して現在のディレクトリにあるすべてのファイルをgrepする実用的な例:

LC_ALL=C find . -type f -exec grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" {} + 

場合によっては、grepを調整することもできます。たとえば、一部の印刷可能なファイルで使用されるBS(0x08-バックスペース)文字、またはVT(0x0B-垂直タブ)を除外するため。BEL(0x07)およびESC(0x1B)文字も、場合によっては印刷可能と見なされます。

Non-Printable ASCII Chars
** marks PRINTABLE but CONTROL chars that is useful to exclude sometimes
Dec   Hex Ctrl Char description           Dec Hex Ctrl Char description
0     00  ^@  NULL                        16  10  ^P  DATA LINK ESCAPE (DLE)
1     01  ^A  START OF HEADING (SOH)      17  11  ^Q  DEVICE CONTROL 1 (DC1)
2     02  ^B  START OF TEXT (STX)         18  12  ^R  DEVICE CONTROL 2 (DC2)
3     03  ^C  END OF TEXT (ETX)           19  13  ^S  DEVICE CONTROL 3 (DC3)
4     04  ^D  END OF TRANSMISSION (EOT)   20  14  ^T  DEVICE CONTROL 4 (DC4)
5     05  ^E  END OF QUERY (ENQ)          21  15  ^U  NEGATIVE ACKNOWLEDGEMENT (NAK)
6     06  ^F  ACKNOWLEDGE (ACK)           22  16  ^V  SYNCHRONIZE (SYN)
7     07  ^G  BEEP (BEL)                  23  17  ^W  END OF TRANSMISSION BLOCK (ETB)
8     08  ^H  BACKSPACE (BS)**            24  18  ^X  CANCEL (CAN)
9     09  ^I  HORIZONTAL TAB (HT)**       25  19  ^Y  END OF MEDIUM (EM)
10    0A  ^J  LINE FEED (LF)**            26  1A  ^Z  SUBSTITUTE (SUB)
11    0B  ^K  VERTICAL TAB (VT)**         27  1B  ^[  ESCAPE (ESC)
12    0C  ^L  FF (FORM FEED)**            28  1C  ^\  FILE SEPARATOR (FS) RIGHT ARROW
13    0D  ^M  CR (CARRIAGE RETURN)**      29  1D  ^]  GROUP SEPARATOR (GS) LEFT ARROW
14    0E  ^N  SO (SHIFT OUT)              30  1E  ^^  RECORD SEPARATOR (RS) UP ARROW
15    0F  ^O  SI (SHIFT IN)               31  1F  ^_  UNIT SEPARATOR (US) DOWN ARROW

更新:私はこれを最近再検討しなければなりませんでした。また、YYMVは端末の設定/太陽天気予報によって異なります。。grepが多くのUnicodeまたは拡張文字を見つけていないことに気づきました直感的には0x80から0xffの範囲と一致するはずですが、3バイトと4バイトのUnicode文字は一致しませんでした。??? 誰かがこれを説明できますか?はい。@frabjousが尋ね、@ calandoaはLC_ALL=C、コマンドのロケールを設定してgrepを一致させるために使用する必要があることを説明しました。

たとえば、私のロケールはLC_ALL=空です

$ locale
LANG=en_IE.UTF-8
LC_CTYPE="en_IE.UTF-8"
.
.
LC_ALL=

LC_ALL=空のgrepは、2バイトのエンコードされた文字に一致しますが、3バイトと4バイトのエンコードされた文字には一致しません。

$ grep -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" notes_unicode_emoji_test
5 copyright c2a9
7:call  underscore c2a0
9:CTRL
31:5 © copyright
32:7 call  underscore

grep with LC_ALL=Cは、必要なすべての拡張文字に一致するようです。

$ LC_ALL=C grep --color='auto' -P -n "[\x80-\xFF]" notes_unicode_emoji_test  
1:���� unicode dashes e28090
3:��� Heart With Arrow Emoji - Emojipedia == UTF8? f09f9298
5:� copyright c2a9
7:call underscore c2a0
11:LIVE��E! ���������� ���� ���������� ���� �� �� ���� ����  YEOW, mix of japanese and chars from other e38182 e38184 . . e0a487
29:1 ���� unicode dashes
30:3 ��� Heart With Arrow Emoji - Emojipedia == UTF8 e28090
31:5  copyright
32:7 call underscore
33:11 LIVE��E! ���������� ���� ���������� ���� �� �� ���� ����  YEOW, mix of japanese and chars from other
34:52 LIVE��E! ���������� ���� ���������� ���� �� �� ���� ����  YEOW, mix of japanese and chars from other
81:LIVE��E! ���������� ���� ���������� ���� �� �� ���� ����  YEOW, mix of japanese and chars from other

このperlの一致(部分的にstackoverflowのどこかで見つかります)または上位の回答の逆grepは、ロケールを設定せずに〜weird〜と〜wonderful〜のすべての「非ASCII」文字を見つけます。

$ grep --color='auto' -P -n "[^\x00-\x7F]" notes_unicode_emoji_test

$ perl -ne 'print "$. $_" if m/[\x00-\x08\x0E-\x1F\x80-\xFF]/' notes_unicode_emoji_test  

1 ‐‐ unicode dashes e28090
3 💘 Heart With Arrow Emoji - Emojipedia == UTF8? f09f9298
5 © copyright c2a9
7 call  underscore c2a0
9 CTRL-H CHARS URK URK URK 
11 LIVEE! あいうえお かが アイウエオ カガ   ซฌ आइ  YEOW, mix of japanese and chars from other e38182 e38184 . . e0a487
29 1 ‐‐ unicode dashes
30 3 💘 Heart With Arrow Emoji - Emojipedia == UTF8 e28090
31 5 © copyright
32 7 call  underscore
33 11 LIVEE! あいうえお かが アイウエオ カガ   ซฌ आइ  YEOW, mix of japanese and chars from other
34 52 LIVEE! あいうえお かが アイウエオ カガ   ซฌ आइ  YEOW, mix of japanese and chars from other
73 LIVEE! あいうえお かが アイウエオ カガ   ซฌ आइ  YEOW, mix of japanese and chars from other

SO優先の非ASCII文字ファインダー:

$ perl -ne 'print "$. $_" if m/[\x00-\x08\x0E-\x1F\x80-\xFF]/' notes_unicode_emoji_test

上の答えのように、逆grep:

$ grep --color='auto' -P -n "[^\x00-\x7F]" notes_unicode_emoji_test

トップの回答と同じですが、WITH LC_ALL=C

$ LC_ALL=C grep --color='auto' -P -n "[\x80-\xFF]" notes_unicode_emoji_test

1
質問の上のコメントで@calandoaとfrabjousのおかげで、grepが2バイトを超えてエンコードされた文字と一致しない理由への回答。grepコマンドの前にLC_ALL = Cを使用してください。
gaoithe

1
800件以上の賛成投票に埋もれた回答を投稿していただき、ありがとうございました。私の問題は0x02文字でした。それが問題であるかどうかを確認するためだけに投稿全体を読む必要はないので、その「実用的な使用例」を一番上に置くことをお勧めします。
Noumenon

1
私は知っています、本当に古い答え、そして耐え難いほどの詳細ですが、私や他の人にとっても正しいと思います。正解です。TLDRを追加しました。上部に。
gaoithe

1

不思議なことに、私は今日これをしなければなりませんでした!(-Pモードでも)grep / egrepを機能させることができなかったため、結局Perlを使用することになりました。何かのようなもの:

cat blah | perl -en '/\xCA\xFE\xBA\xBE/ && print "found"'

ユニコード文字(\u2212以下の例のような)の場合、これを使用します:

find . ... -exec perl -CA -e '$ARGV = @ARGV[0]; open IN, $ARGV; binmode(IN, ":utf8"); binmode(STDOUT, ":utf8"); while (<IN>) { next unless /\N{U+2212}/; print "$ARGV: $&: $_"; exit }' '{}' \;

1

1つのUnicode文字を検索する方法を知るのは興味深いかもしれません。このコマンドが役立ちます。あなたはUTF8のコードを知る必要があるだけです

grep -v $'\u200d'

私は実際には専門家ではありませんが、それがUTF8表現ではないこと、UTF16、またはおそらくUTF32、あるいはUCS16であることを十分に知っています。2バイトのコードポイントの場合、これら3つはすべて同じになる可能性があります。
Baxissimo 2018

1

ASCII以外のすべての文字を見つけると、Unicode文字列を探している、または文字を個別に削除しようとしているように見えます。

前者については、次のいずれかを試してください(変数fileは自動化に使用されます)。

 file=file.txt ; LC_ALL=C grep -Piao '[\x80-\xFF\x20]{7,}' $file | iconv -f $(uchardet $file) -t utf-8

 file=file.txt ; pcregrep -iao '[\x80-\xFF\x20]{7,}' $file | iconv -f $(uchardet $file) -t utf-8

 file=file.txt ; pcregrep -iao '[^\x00-\x19\x21-\x7F]{7,}' $file | iconv -f $(uchardet $file) -t utf-8

以前の回答で述べたように、LC_ALL = Cがないと、Vanilla grepは正しく機能しません。

ASCII範囲はx00-x7F、スペースはx20文字列にあるため、負の範囲は省略されます。

x80-xFF文字列にスペースがあるため、ASCII以外の範囲はです。正の範囲に追加されます。

文字列は、範囲内の少なくとも7つの連続した文字であると想定されています。{7,}

シェルが読み取り可能な出力の場合、uchardet $file自動補間のためにiconvに渡されるファイルエンコーディングの推測を返します。


uchardetコマンドについて言及しているため、これは非常に便利です。そのヘッドアップをありがとう!
bballdave025
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.