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

답변:


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
옵션을 grep지원하지 않기 때문에 BSD (OS X 10.8 Mountain Lion)에서는 작동하지 않습니다 P.
Bastiaan M. van de Weerd

20
마지막 의견을 업데이트하기 위해 GNU의 버젼은 grepHomebrew의 dupes라이브러리 에서 사용할 수 있습니다 (를 사용하여 활성화 brew tap homebrew/dupes) :brew install grep
Bastiaan M. van de Weerd

48
@BastiaanVanDeWeerd는 정확합니다. OSX 10.8의 grep은 Darwin이 GNU grep 대신 BSD 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

22
ag "[\x80-\xFF]" file설치 만하면 되는 Mac에서 잘 작동합니다.the_silver_searcher
slf

123

ASCII가 아닌 문자의 바이트 범위에 대해 가정하는 대신 위의 솔루션 대부분이 그러 하듯이 대신 ASCII 문자의 실제 바이트 범위에 대해 명시 적으로 나타내는 것이 IMO보다 약간 좋습니다.

예를 들어 첫 번째 솔루션은 다음과 같습니다.

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

(기본적으로 16 진 ASCII 범위를 벗어난 모든 문자에 대해 grep : \ x00에서 \ x7F까지)

하지 작업 것이다 마운틴 라이온에 (때문에 BSD의 GREP에서 PCRE 지원의 부족) 과 함께 있지만, pcre브루 통해 설치 한 다음 그냥 잘 작동합니다 :

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

누구나 생각할 수있는 장단점?


9
이것은 실제로 위의 솔루션이 실패한 곳에서 효과적이었습니다. M $ Word 아포스트로피를 찾는 것은 쉽지 않았습니다!
AlbertEngelB

2
bash 호환 쉘이 있지만 pcre-grep이 작동 LC_COLLATE=C grep $'[^\1-\177]'하지 않으면 작동합니다 (널 바이트가없는 파일의 경우)
idupree

2
이 솔루션은 위의 솔루션보다 일관되게 작동하는 것 같습니다.
0xcaff

1
"[\ x80- \ xFF]"를 사용하여 UTF8 파일에서 Kanji, Cyrillic 및 Traditional Chinese를 가져 오기 위해 이것을 사용해야했습니다.
buckaroo1177125

1
장점은 다른 옵션은 훌륭하지만 좋지는 않았지만 훌륭하게 작동한다는 것입니다. 지금까지 단점이 발견되지 않았습니다.
jwpfox

67

다음은 나를 위해 작동합니다.

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

비 ASCII 문자는 0x80에서 시작하여 바이트를 볼 때 0xFF로 이동합니다. Grep (및 제품군)은 멀티 바이트 문자를 단일 엔티티로 병합하여 원하는 정규 표현식 일치를 위해 유니 코드 처리를 수행하지 않습니다. -P내 grep 의 옵션을 사용하면 \xdd캐릭터 클래스에서 이스케이프를 사용하여 원하는 것을 얻을 수 있습니다.


1
여러 파일에서 이것을 호출하는 방법을 즉시 알지 못할 수도있는 뷰의 경우 find를 실행하십시오. -name * .xml | xargs grep -P "[\ x80- \ xFF]"
David Mohundro

1
이것은 일치를 반환하지만 캐릭터가 무엇이며 어디에 있는지에 대한 표시는 없습니다. 캐릭터가 무엇이며 어디에 있는지 어떻게 알 수 있습니까?
Faheem Mitha

"-n"을 추가하면 행 번호가 표시되고, 추가로 보이지 않는 문자가 터미널에 블록으로 표시됩니다. grep -n -P "[\ x80- \ xFF]"file.xml
fooMonster

4
한글 한국어에 문제가 있습니다. echo '소녀시대' | grep -P "[\x80-\xFF]"아무 것도 반환하지 않습니다 . 다른 사람이 확인할 수 있습니까? (GNU grep 2.21)
frabjous

@frabjous 여기에서도 동일하지만 역효과를 모으기 : echo '소녀시대' | grep -P "[^\x00-\x7F]". 또는 the_silver_searcher@slf가 지적한대로 사용 하십시오 :echo '소녀시대' | ag "[\x80-\xFF]"
psmith

55

펄에서

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

1
OSX10.11에서 실제로 작동하는 것을 찾기 전에 몇 가지 grep + regex 솔루션을 시도해야했습니다
sg

OSX 솔루션 @ sg를 공유 하시겠습니까?!
지리학

위의 펄 스크립트는 제가 말하고있는 해결책입니다
sg

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

43

쉬운 방법은 비 ASCII 문자를 ASCII 문자가 아닌 문자로 정의하는 것입니다.

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

^필요한 경우 탭을 추가하십시오 .

설정 LC_COLLATE=C하면 많은 로케일에서 문자 범위의 의미에 대한 놀라운 놀라움을 피할 수 있습니다. LC_CTYPE=C1 바이트 문자를 일치시키기 위해 설정 이 필요합니다. 그렇지 않으면 명령이 현재 인코딩에서 유효하지 않은 바이트 시퀀스를 놓치게됩니다. 설정 LC_ALL=C은 로케일에 따른 영향을 완전히 피합니다.


tcsh가있는 RedHat 6.4에서는 <<< env LC_COLLATE = C grep -n '[^-~]'file.xml >>>을 사용해야했습니다. 줄 번호를 얻기 위해 -n을 추가했습니다.
ddevienne

나를 echo "A" | LC_COLLATE=C grep '[^ -~]'위해 경기를 반환
frabjous

1
@frabjous가있는 경우 설정 LC_ALL=en_US.UTF-8보다 우선합니다 LC_COLLATE. 당신은 당신의 환경에서 이것을 가지고 있으면 안됩니다! LC_ALL특정 작업이 특정 로케일을 사용하도록 강제하는 것 C입니다. 모든 범주에 대한 기본 로캘을 설정하려면을 설정하십시오 LANG.
Gilles 'SO- 악마 그만해'

1
처음에는 LC_ALL=CMac OS X와 ​​Ubuntu에서 다르게 동작합니다. 이 설정을 추가하면 동일한 결과가 나타납니다.
Max Peng

1
이것은 Mac에서 작동하지만 다른 grep 기반 솔루션은 작동하지 않습니다.
Matthias Fripp

26

허용 된 답변에서 grep 검색과 완전히 다른 결과를 얻은 다른 변형이 [\x80-\xFF]있습니다. 아마도 비 ASCII 문자를 찾는 것이 누군가에게 유용 할 것입니다.

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

참고 : 내 컴퓨터의 grep (Mac)에는 -P옵션 brew install grepggrep없으므로을 대신하여 위의 전화를 걸었습니다 grep.


2
Mac뿐만 아니라 Linux에서도 작동하기 때문에 이것이 가장 좋은 대답입니다.
tommy.carstensen

Linux에서 나를 위해 일한 사람 만.

9

다음 코드가 작동합니다.

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

대체 /tmp당신은을 통해 검색 할 디렉토리의 이름으로.


2
Mac에서는 이것이 작동하지만 grep 기반의 대부분은 그렇지 않습니다.
Matthias Fripp

9

인쇄 할 수없는 문자를 검색합니다. TLDR; 행정상 개요

  1. 제어 문자 및 확장 유니 코드 검색
  2. 로케일 설정, 예를 들어 LC_ALL=Cgrep이 확장 유니 코드로 예상되는 것을 수행하도록하는 데 필요

선호하는 비 ASCII 문자 찾기 :

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

상단 답변에서와 같이 역 그렙 :

$ 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 는 "use this :" [^\n -~]"를 제안 합니다. DOS 텍스트 파일에는 \ r을 추가하십시오." [^\x0A\x020-\x07E]"로 번역되고 CR에는 \ x0D를 추가합니다"

또한 grep에 -c (일치 된 패턴 수 표시)를 추가하면 일치하는 문자열이 터미널을 망칠 수 있으므로 인쇄 할 수없는 문자를 검색 할 때 유용합니다.

범위 0-8과 0x0e-0x1f (0x80-0xff 범위)를 추가하는 것이 유용한 패턴이라는 것을 알았습니다. TAB, CR 및 LF와 하나 또는 두 개 이상의 인쇄 할 수없는 문자는 제외됩니다. 따라서 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

예를 들어 현재 디렉토리 아래의 모든 파일을 grep하는 find 사용 예제 :

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

때때로 grep을 조정하고 싶을 수도 있습니다. 예를 들어 일부 인쇄 가능한 파일에 사용되거나 VT (0x0B-세로 탭)를 제외하기 위해 BS (0x08-백 스페이스) 문자가 사용됩니다. 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 BUT. . grep이 많은 유니 코드 또는 확장 문자를 찾지 못했음을 알았습니다 . 직관적으로 0x80 ~ 0xff 범위와 일치해야하지만 3 및 4 바이트 유니 코드 문자는 일치하지 않습니다. ??? 누구든지 이것을 설명 할 수 있습니까? 예. @frabjous ask 및 @calandoa는 LC_ALL=Cgrep이 일치하도록 명령의 로케일을 설정하는 데 사용해야한다고 설명했습니다 .

예를 들어 내 로케일이 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 match (부분적으로 stackoverflow의 다른 곳에서 발견됨) 또는 최상위 답변 DO의 역 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

선호하는 비 ASCII 문자 찾기 :

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

상단 답변에서와 같이 역 그렙 :

$ 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
grep이 @calandoa 덕분에 2 바이트 이상으로 인코딩 된 문자와 일치하지 않는 이유에 대한 답변과 위의 질문에 대한 논평에서 frabjous. grep 명령 전에 LC_ALL = C를 사용하십시오.
gaoithe

1
800 명의 다른 공감대에 묻힌 답변을 게시 해 주셔서 감사합니다! 내 문제는 0x02 문자였습니다. "실제적인 사용 예"를 가장 가까이에두고 싶을 수도 있습니다. 문제가 있는지 확인하기 위해 전체 게시물을 읽을 필요는 없기 때문입니다.
누 메논 September

1
나는 정말 오래된 대답과 극심한 세부 사항을 알고 있지만 나와 다른 사람들에게도 유용합니다. 당신 말이 맞습니다. TLDR을 추가했습니다. 맨 위에.
gaoithe

1

이상하게도 나는 오늘 이것을해야했다! grep / egrep을 작동시킬 수 없기 때문에 Perl을 사용했습니다 (-P 모드에서도). 다음과 같은 것 :

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

하나의 유니 코드 문자를 검색하는 방법을 아는 것이 흥미로울 수 있습니다. 이 명령이 도움이 될 수 있습니다. UTF8의 코드 만 알아야합니다.

grep -v $'\u200d'

나는 실제로 전문가는 아니지만 UTF8 표현이 아니며 UTF16 또는 UTF32 또는 UCS16이라는 것을 알기에 충분합니다. 2 바이트 코드 포인트의 경우이 세 개가 모두 동일 할 수 있습니다.
Baxissimo

1

ASCII가 아닌 모든 문자를 찾으면 유니 코드 문자열을 찾고 있거나 해당 문자를 개별적으로 제거하려는 느낌이 듭니다.

전자의 경우 다음 중 하나를 시도하십시오 (변수 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가 없으면 바닐라 grep이 올바르게 작동하지 않습니다.

문자열은 음수 범위에 생략 된 공백이 있으므로 ASCII 범위는 x00-x7F, 공백은 x20입니다.

비 ASCII 범위는입니다 x80-xFF. 문자열에는 양의 범위가 추가하는 공백이 있기 때문입니다.

문자열은 범위 내에서 7 자 이상의 연속 문자 인 것으로 가정합니다. {7,}.

쉘 읽기 가능 출력 uchardet $file의 경우 자동 보간을 위해 iconv에 전달 된 파일 인코딩의 추측을 리턴합니다.


이것은 uchardet명령 에 대한 언급으로 인해 매우 유용합니다 . 고마워요!
bballdave025
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.