Jak mogę grep dla wszystkich znaków spoza ASCII?

Mam kilka bardzo dużych plików XML i próbuję znaleźć linie, które zawierają znaki inne niż ASCII. Próbowałem:

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

Ale to zwraca każdą linię w pliku, niezależnie od tego, czy linia zawiera znak w określonym zakresie.

Czy źle zrozumiałam składnię, czy robię coś innego? Też próbowałem:

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

(z pojedynczymi i podwójnymi cudzysłowami otaczającymi wzór).

Author: kenorb, 2010-06-09

10 answers

Możesz użyć polecenia:

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

To da ci numer linii i podświetli znaki inne niż ascii na Czerwono.

W niektórych systemach, w zależności od twoich ustawień, powyższe nie zadziała, więc możesz grepować przez odwrotność

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

Zauważ również, że ważnym bitem jest znacznik -P, który odpowiada --perl-regexp: więc będzie interpretował Twój wzorzec jako wyrażenie regularne Perla. Mówi również, że

Jest to wysoce eksperymentalne i grep-P może ostrzegać przed unimplemented funkcje.

 414
Author: jerrymouse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-09 14:54:33

Zamiast zakładać zakres bajtów znaków nie-ASCII, jak większość powyższych rozwiązań, IMO jest nieco lepiej, IMO, aby być wyraźnym co do rzeczywistego zakresu bajtów znaków ASCII.

Więc pierwszym rozwiązaniem będzie np.:

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

(który w zasadzie greps dla dowolnego znaku spoza zakresu ASCII w systemie szesnastkowym: od \x00 do \x7f)

Na Mountain Lion, który nie działa (z powodu braku wsparcia PCRE w BSD grep) , ale z pcre zainstalowanym za pomocą Homebrew, następujące rzeczy będą działać równie dobrze:

pcregrep --color='auto' -n '[^\x00-\x7F]' file.xml
Jakieś plusy i minusy, które każdy może wymyślić?
 100
Author: pvandenberk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-04 12:25:41

Dla mnie działa:

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

Znaki inne niż ASCII zaczynają się od 0x80 i przechodzą do 0xFF, gdy patrząc na bajty. Grep (i rodzina) nie przetwarza Unicode, aby scalić wielbajtowe znaki w jeden obiekt w celu dopasowania wyrażeń regularnych, jak chcesz. Opcja -P w moim grepie pozwala na użycie ucieczki \xdd w klasach znaków, aby osiągnąć to, co chcesz.

 66
Author: Thelema,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-08 21:59:22

W Perlu

perl -ane '{ if(m/[[:^ascii:]]/) { print  } }' fileName > newFile
 46
Author: noquery,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-10 14:05:58

Najprostszym sposobem jest zdefiniowanie znaku nie-ASCII... jako znak, który nie jest znakiem ASCII.

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

Dodaj zakładkę po ^ w razie potrzeby.

Ustawienie LC_COLLATE=C pozwala uniknąć przykrych niespodzianek dotyczących znaczenia zakresów znaków w wielu lokalizacjach. Ustawienie LC_CTYPE=C jest konieczne do dopasowania znaków jednobajtowych - w przeciwnym razie polecenie pominie niepoprawne sekwencje bajtów w bieżącym kodowaniu. Ustawienie LC_ALL=C pozwala całkowicie uniknąć efektów zależnych od ustawień lokalnych.

 34
Author: Gilles,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-15 13:03:04

Oto kolejny wariant, który dał całkowicie Inne wyniki wyszukiwania grep dla [\x80-\xFF] w zaakceptowanej odpowiedzi. Być może przyda się komuś znalezienie dodatkowych znaków nie-ascii:

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

Uwaga: mój komputer grep (Mac) nie miał opcji -P, więc zrobiłem brew install grep i rozpocząłem powyższe wywołanie od ggrep zamiast grep.

 19
Author: ryanm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-23 17:00:21

Działa następujący kod:

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

Zastąp /tmp nazwą katalogu, który chcesz przeszukać.

 6
Author: user7417071,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 23:02:41

O dziwo, musiałem to zrobić dzisiaj! Skończyło się na użyciu Perla, ponieważ nie mogłem uruchomić grep/egrep (nawet w trybie-P). Coś w stylu:

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

Dla znaków unicode (jak \u2212 w przykładzie poniżej) użyj tego:

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
Author: dty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-16 12:51:39

Wyszukiwanie znaków niedrukowalnych.

Zgadzam się z Harvey powyżej Zakopane w komentarzach, często bardziej przydatne jest wyszukiwanie znaków niedrukowalnych lub łatwo jest myśleć nie-ASCII, kiedy naprawdę powinieneś myśleć nie-drukowalne. Harvey sugeruje "użyj tego: "[^\N -~]". Dodaj \r dla plików tekstowych DOS. To tłumaczy się na "[^\x0a\x020 -\x07e] "i dodaje \x0d dla CR"

Ponadto, dodanie -c (Pokaż liczbę dopasowanych wzorców) do grepa jest przydatne, gdy wyszukiwanie niedrukowalnych znaków jako dopasowanych łańcuchów może zepsuć terminal.

Znalazłem dodanie zakresu 0-8 i 0x0e-0x1f (do zakresu 0x80 - 0xff) jest użytecznym wzorcem. Nie dotyczy to tabulatorów, CR i LF oraz jednego lub dwóch innych nietypowych znaków drukowalnych. Więc IMHO całkiem przydatnym (choć prymitywnym) wzorem grepa jest ten:

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

Podział:

\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

Np. praktyczny przykład użycia find do grepowania wszystkich plików w bieżącym katalogu:

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

Możesz chcieć dostosować czasami grep. np. znak BS(0x08 - backspace) używany w niektórych plikach do druku lub do wykluczenia VT (0x0b-vertical tab). Znaki BEL(0X07) i ESC (0X1B) mogą być również uważane za drukowalne w niektórych przypadkach.

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
 1
Author: gaoithe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-21 12:42:27

Może być interesujące wiedzieć, jak wyszukać jeden znak unicode. To polecenie może pomóc. Musisz tylko znać kod w UTF8

grep -v $'\u200d'
 0
Author: arezae,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 23:19:11