如何grep所有非ASCII字符?

pco*_*rey 348 regex unix unicode grep

我有几个非常大的XML文件,我试图找到包含非ASCII字符的行.我尝试过以下方法:

grep -e "[\x{00FF}-\x{FFFF}]" file.xml
Run Code Online (Sandbox Code Playgroud)

但是这会返回文件中的每一行,无论该行是否包含指定范围内的字符.

我的语法有错吗?或者我做错了什么?我也尝试过:

egrep "[\x{00FF}-\x{FFFF}]" file.xml 
Run Code Online (Sandbox Code Playgroud)

(模式周围有单引号和双引号).

jer*_*use 465

您可以使用以下命令:

grep --color='auto' -P -n "[\x80-\xFF]" file.xml
Run Code Online (Sandbox Code Playgroud)

这将为您提供行号,并以红色突出显示非ascii字符.

在某些系统中,根据您的设置,上述操作无效,因此您可以通过反向操作

grep --color='auto' -P -n "[^\x00-\x7F]" file.xml
Run Code Online (Sandbox Code Playgroud)

另请注意,重要的位是-P等于的标志--perl-regexp:因此它将您的模式解释为Perl正则表达式.它也说

这是高度实验性的,grep -P可能会警告未实现的功能.

  • @BastiaanVanDeWeerd是正确的,OSX 10.8上的grep不再支持PCRE("Perl兼容的正则表达式"),因为Darwin现在使用BSD grep而不是GNU grep.安装`dupes`库的另一种方法是安装`pcre`代码:`brew install pcre` ...作为其中的一部分,你将得到`pcregrep`实用程序,你可以按如下方式使用它:`pcregrep - color ='auto'-n"[\ x80-\xFF]"file.xml` (46认同)
  • 这不适用于BSD`grep`(在OS X 10.8 Mountain Lion上),因为它不支持`P`选项. (36认同)
  • 为了更新我的最后评论,GNU版本的`grep`可以在Homebrew的`dupes`库中使用(启用使用`brew tap homebrew/dupes`):`brew install grep` (20认同)
  • 这适用于mac`ag"[\ x80-\xFF]"文件`你需要安装`the_silver_searcher` (20认同)
  • 对于Mac` brew`用户,可以使用`brew install coreutils`安装[GNU的coreutils](https://www.gnu.org/software/coreutils/).这将为您提供许多前缀为'g'的GNU工具 - 在本例中使用`ggrep`.这应该避免因更换系统实用程序而引起的问题,因为系统特定的Mac脚本现在依赖于BSD grep. (15认同)
  • 使用`LC_ALL = C`前缀此命令!在我的系统上(其中`LANG = en_US.UTF-8`),单独这个命令无法在UTF-8文件中找到经常使用的撇号'(`右单引号'/`U + 2019`)通过MS软件,而不是ASCII软件 (6认同)
  • 韩语韩语有问题:`echo'소녀시대'| grep -P"[\ x80-\xFF]"`什么都不给我回报 - 其他人都可以确认吗?(GNU grep 2.21) (3认同)
  • @JoelPurra coreutils似乎不包括grep. (2认同)

pva*_*erk 119

正如大多数上述解决方案所做的那样,不是对非ASCII字符的字节范围做出假设,而是明确更好地了解ASCII字符的实际字节范围.

所以第一个解决方案将成为:

grep --color='auto' -P -n '[^\x00-\x7F]' file.xml
Run Code Online (Sandbox Code Playgroud)

(基本上对于十六进制ASCII范围之外的任何字符进行greps:从\ x00到\ x7F)

在Mountain Lion上无法工作(由于缺少BSD grep中的PCRE支持),但是pcre通过Homebrew安装,以下内容也可以正常工作:

pcregrep --color='auto' -n '[^\x00-\x7F]' file.xml
Run Code Online (Sandbox Code Playgroud)

任何人可以想到的任何利弊?

  • 这实际上适用于上述解决方案失败的地方.找到M $ Word撇号并不容易! (9认同)
  • 如果您具有兼容bash的shell,但不能使用pcre-grep,则可以使用LC_COLLATE = C grep $'[^ \ 1- \ 177]'(适用于无空字节的文件) (2认同)
  • 这个解决方案似乎比上面的解决方案更加一致. (2认同)

The*_*ema 67

以下适用于我:

grep -P "[\x80-\xFF]" file.xml
Run Code Online (Sandbox Code Playgroud)

非ASCII字符从0x80开始,在查看字节时转到0xFF.Grep(和系列)不进行Unicode处理,将多字节字符合并到单个实体中,以便进行正则表达式匹配.-P我的grep中的选项允许\xdd在字符类中使用转义来完成你想要的.

  • 韩语韩语有问题:`echo'소녀시대'| grep -P"[\ x80-\xFF]"`什么都不给我回报 - 其他人都可以确认吗?(GNU grep 2.21) (4认同)

noq*_*ery 51

在perl

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

  • `perl -lne'打印if/[^ [:ascii:]] /'file.xml` (5认同)
  • 好的解决方案 Perl很擅长这种事情. (3认同)

Gil*_*il' 41

简单的方法是将非ASCII字符定义为不是ASCII字符的字符.

LC_ALL=C grep '[^ -~]' file.xml
Run Code Online (Sandbox Code Playgroud)

^如有必要,请在添加选项卡后添加.

设置LC_COLLATE=C避免了许多语言环境中关于字符范围含义的令人讨厌的意外.设置LC_CTYPE=C是匹配单字节字符所必需的 - 否则命令将错过当前编码中的无效字节序列.设置LC_ALL=C完全避免了与语言环境相关的影响.

  • 这适用于 Mac,而其他基于 grep 的解决方案则不然。 (3认同)
  • @frabjous 如果你有 `LC_ALL=en_US.UTF-8`,那就胜过 `LC_COLLATE` 设置。你的环境中不应该有这个!`LC_ALL` 只是强制特定任务使用特定的语言环境,通常是 `C`。要为所有类别设置默认语言环境,请设置“LANG”。 (2认同)

rya*_*anm 24

这是我发现的另一个变体,它在接受的答案中产生了与grep搜索完全不同的结果[\x80-\xFF].也许有人找到额外的非ascii字符会很有用:

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

注意:我的计算机的grep(Mac)没有-P选项,所以我做了brew install grep并开始上面的调用ggrep而不是grep.

  • 到目前为止,这是最好的答案,因为它适用于Mac和Linux。 (2认同)

小智 9

以下代码有效:

find /tmp | perl -ne 'print if /[^[:ascii:]]/'
Run Code Online (Sandbox Code Playgroud)

替换/tmp为要搜索的目录的名称.

  • 在 Mac 上,这有效,而大多数基于 grep 的则无效。 (2认同)

gao*_*the 7

搜索不可打印的字符。TLDR;执行摘要

  1. 搜索控制字符和扩展的unicode

  2. 语言环境设置,例如LC_ALL = C,以使grep执行扩展的unicode所期望的操作

因此,首选的非ascii字符查找器:

$ perl -ne'打印“ $。$ _”如果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”

另外,在搜索不可打印的字符时,向grep添加-c(显示匹配模式的计数)非常有用,因为匹配的字符串可能会使终端混乱。

我发现将范围0-8和0x0e-0x1f(添加到0x80-0xff范围)是一个有用的模式。这不包括TAB,CR和LF以及一个或两个以上不常见的可打印字符。因此,恕我直言,一个非常有用的(尽管是粗糙的)grep模式是这样的:

grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" *
Run Code Online (Sandbox Code Playgroud)

实际上,通常您需要执行以下操作:

LC_ALL=C grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" *
Run Code Online (Sandbox Code Playgroud)

分解:

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
Run Code Online (Sandbox Code Playgroud)

例如,使用find的实际示例grep grep当前目录下的所有文件:

LC_ALL=C find . -type f -exec grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" {} + 
Run Code Online (Sandbox Code Playgroud)

您可能希望有时调整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
Run Code Online (Sandbox Code Playgroud)

更新:我最近不得不重新审视它。并且,YYMV取决于终端设置/太阳能天气预报BUT。。我注意到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=
Run Code Online (Sandbox Code Playgroud)

带有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
Run Code Online (Sandbox Code Playgroud)

具有LC_ALL = C的grep似乎与您想要的所有扩展字符匹配:

$ 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
Run Code Online (Sandbox Code Playgroud)

这个perl匹配项(部分在stackoverflow上的其他地方找到)或最上面答案的反grep似乎确实找到了所有〜weird〜和〜wonderful〜“ non-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 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
73 LIVE?E! ????? ?? ????? ?? ? ? ?? ??  YEOW, mix of japanese and chars from other
Run Code Online (Sandbox Code Playgroud)

因此,首选的非ascii字符查找器:

$ perl -ne'打印“ $。$ _”如果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