¿Cómo grep para todos los caracteres que no son ASCII?

Tengo varios archivos XML muy grandes y estoy tratando de encontrar las líneas que contienen caracteres que no son ASCII. He intentado lo siguiente:

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

Pero esto devuelve cada línea en el archivo, independientemente de si la línea contiene un carácter en el rango especificado.

¿Tengo la syntax incorrecta o estoy haciendo algo diferente? También lo intenté:

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

(con comillas simples y dobles que rodean el patrón).

Puedes usar el comando:

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

Esto le dará el número de línea y resaltará caracteres no ascii en rojo.

En algunos sistemas, dependiendo de su configuración, lo anterior no funcionará, por lo que puede grep por el inverso

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

Tenga en cuenta también que el bit importante es el indicador -P que equivale a --perl-regexp : por lo tanto, interpretará su patrón como una expresión regular de Perl. También dice que

esto es altamente experimental y grep -P puede advertir sobre las características no implementadas.

En lugar de hacer suposiciones sobre el rango de bytes de los caracteres que no son ASCII, como lo hacen la mayoría de las soluciones anteriores, es ligeramente mejor IMO para ser explícito sobre el rango real de bytes de los caracteres ASCII.

Entonces, la primera solución, por ejemplo, sería:

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

(que básicamente greps para cualquier carácter fuera del rango ASCII hexadecimal: desde \ x00 hasta \ x7F)

En Mountain Lion eso no funcionará (debido a la falta de soporte de PCRE en grep BSD) , pero con pcre instalado a través de Homebrew, lo siguiente funcionará igual de bien:

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

¿Alguna ventaja o desventaja que alguien pueda pensar?

Lo siguiente funciona para mí:

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

Los caracteres que no son ASCII comienzan en 0x80 y van a 0xFF cuando se buscan bytes. Grep (y su familia) no procesan en Unicode para fusionar caracteres de varios bytes en una sola entidad para la coincidencia de expresiones regulares, como parece querer. La opción -P en mi grep permite el uso de escapes \xdd en las clases de caracteres para lograr lo que quieres.

En perl

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

La manera fácil es definir un carácter no ASCII … como un carácter que no es un carácter ASCII.

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

Agregue una pestaña después de ^ si es necesario.

Establecer LC_COLLATE=C evita sorpresas desagradables sobre el significado de los rangos de caracteres en muchos entornos. La configuración de LC_CTYPE=C es necesaria para hacer coincidir caracteres de un solo byte; de ​​lo contrario, el comando perdería secuencias de bytes inválidas en la encoding actual. El ajuste LC_ALL=C evita por completo los efectos dependientes de la configuración regional.

Aquí hay otra variante que encontré que produjo resultados completamente diferentes de la búsqueda grep para [\x80-\xFF] en la respuesta aceptada. Tal vez sea útil para alguien encontrar caracteres adicionales no ascii:

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

Nota: el grep de mi computadora (una Mac) no tenía la opción -P , así que hice brew install grep y comencé la llamada anterior con ggrep lugar de grep .

El siguiente código funciona:

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

Reemplace /tmp con el nombre del directorio por el que desea buscar.

¡Extraño, tuve que hacer esto hoy! Terminé usando Perl porque no pude hacer que grep / egrep funcionara (incluso en modo -P). Algo como:

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

Para caracteres Unicode (como \u2212 en el ejemplo a continuación), usa esto:

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

Búsqueda de caracteres no imprimibles.

Estoy de acuerdo con Harvey antes mencionado en los comentarios, a menudo es más útil buscar caracteres no imprimibles O es fácil pensar que no es ASCII cuando realmente debería pensar que no es imprimible. Harvey sugiere “use esto:” [^ \ n – ~] “. Agregue \ r para archivos de texto DOS. Eso se traduce en” [^ \ x0A \ x020- \ x07E] “y agregue \ x0D para CR”.

Además, agregar -c (mostrar el recuento de los patrones combinados) a grep es útil cuando se buscan caracteres no imprimibles, ya que las cadenas coincidentes pueden arruinar el terminal.

Encontré que agregar un rango de 0-8 y 0x0e-0x1f (al rango de 0x80-0xff) es un patrón útil. Esto excluye el TAB, CR y LF y uno o dos caracteres imprimibles poco comunes. Así que, en mi humilde opinión, un patrón de grep bastante útil (aunque crudo) es ESTE:

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

Descompostura:

 \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 

Ejemplo práctico de uso find para grep todos los archivos en el directorio actual:

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

Es posible que desee ajustar el grep a veces. por ejemplo, BS (0x08 – backspace) char utilizado en algunos archivos imprimibles o para excluir VT (0x0B – pestaña vertical). Los caracteres BEL (0x07) y ESC (0x1B) también se pueden considerar imprimibles en algunos casos.

 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 

Podría ser interesante saber cómo buscar un carácter unicode. Este comando puede ayudar. Solo necesita saber el código en UTF8

 grep -v $'\u200d'