Tengo algunos volcados de base de datos de un sistema Windows en mi caja. Son archivos de texto. Estoy usando cygwin para grep a través de ellos. Estos parecen ser archivos de texto sin formato; los abro con editores de texto como bloc de notas y wordpad y parecen legibles. Sin embargo, cuando ejecuto grep en ellos, dirá binary file foo.txt matches.

He notado que los archivos contienen algunos caracteres ascii NUL, que creo que son artefactos del volcado de la base de datos.

Entonces, ¿qué hace que grep considere que estos archivos son binarios? ¿El carácter NUL? ¿Hay una bandera en el sistema de archivos? ¿Qué necesito cambiar para que grep sea mostrarme las coincidencias de línea?

Comentarios

  • --null-data puede ser útil si NUL es el delimitador.

Responder

Si hay un NUL en cualquier parte del archivo, grep lo considerará como un archivo binario.

Podría existir una solución alternativa como esta cat file | tr -d "\000" | yourgrep para eliminar todo nulo primero, y luego para buscar en el archivo.

Comentarios

  • … o use -a / --text, al menos con GNU grep.
  • @derobert: en realidad, en algunos sistemas (más antiguos), grep ve líneas, pero su salida truncará cada línea coincidente en la primera NUL (probablemente porque llama a C ‘ s printf y le da la línea correspondiente?). En un sistema de este tipo, grep cmd .sh_history devolverá tantas líneas vacías como líneas coincidan con ‘ cmd ‘, ya que cada línea de sh_history tiene un formato específico con un NUL al principio de cada línea. (pero su comentario » al menos en GNU grep » probablemente se haga realidad. Yo no ‘ No tengo uno a mano ahora para probar, pero espero que lo manejen bien)
  • ¿Es la presencia de un carácter NUL el único criterio? Lo dudo. Es ‘ probablemente más inteligente que eso. Cualquier cosa que caiga fuera del rango Ascii 32-126 sería mi suposición, pero ‘ tendríamos que mirar el código fuente para estar seguros.
  • Mi información era desde la página de manual de la instancia grep específica. Su comentario sobre la implementación es válido, la fuente triunfa sobre los documentos.
  • Tenía un archivo que grep en cygwin se consideraba binario porque tenía un guión largo (0x96) en lugar de un guión / menos ASCII regular (0x2d). Supongo que esta respuesta resolvió el problema de OP ‘, pero parece que está incompleta.

Respuesta

grep -a funcionó para mí:

$ grep --help [...] -a, --text equivalent to --binary-files=text 

Comentarios

  • Esta es la mejor respuesta, la menos costosa, en mi opinión.
  • Pero no cumple con POSIX
  • ¿Le importaría explicar por qué no lo es? Sería bueno dejarlo claro, para todos los que encontramos esta respuesta como una opción. Gracias :).
  • Hola, ‘ he venido aquí por SEGUNDA vez para volver a aprender esto LOL. Un acento francés (diacrítico) en el texto estaba causando que grep vocifera

Responder

Puede usar el strings utilidad para extraer el contenido de texto de cualquier archivo y luego canalizarlo a través de grep, así: strings file | grep pattern.

Comentarios

  • Ideal para grepping de archivos de registro que pueden estar parcialmente dañados
  • sí, a veces registro binario mixto también sucede. Esto es bueno.

Respuesta

GNU grep 2.24 RTFS

Conclusión: solo 2 y 2 casos:

  • NUL, por ejemplo printf "a\0" | grep "a"

  • error de codificación de acuerdo con C99 mbrlen(), por ejemplo:

    export LC_CTYPE="en_US.UTF-8" printf "a\x80" | grep "a" 

    porque \x80 no puede ser el primer byte de un punto Unicode UTF-8: UTF-8 – Descripción | en.wikipedia.org

Además, como menciona Stéphane Chazelas ¿Qué hace que grep considere un archivo para ser binario? | Unix & Linux Stack Exchange , esas comprobaciones solo se realizan hasta la primera lectura del búfer de longitud TODO.

Solo hasta el primer búfer leído

Por lo tanto, si ocurre un error de codificación o NUL en medio de un archivo muy grande, ser grepped de todos modos.

Me imagino que esto es por razones de rendimiento.

Por ejemplo: esto imprime la línea:

printf "%10000000s\n\x80a" | grep "a" 

pero esto no:

printf "%10s\n\x80a" | grep "a" 

El tamaño real del búfer depende de cómo se lea el archivo. P.ej.comparar:

export LC_CTYPE="en_US.UTF-8" (printf "\n\x80a") | grep "a" (printf "\n"; sleep 1; printf "\x80a") | grep "a" 

Con sleep, la primera línea se pasa a grep incluso si es de solo 1 byte mucho tiempo porque el proceso entra en suspensión y la segunda lectura no comprueba si el archivo es binario.

RTFS

git clone git://git.savannah.gnu.org/grep.git cd grep git checkout v2.24 

Encuentre dónde está codificado el mensaje de error stderr:

git grep "Binary file" 

Nos lleva a /src/grep.c:

if (!out_quiet && (encoding_error_output || (0 <= nlines_first_null && nlines_first_null < nlines))) { printf (_("Binary file %s matches\n"), filename); 

Si esas variables estaban bien nombradas, básicamente llegamos a la conclusión.

encoding_error_output

Quick grepping para encoding_error_output muestra que la única ruta de código que puede modificarlo pasa por buf_has_encoding_errors:

clen = mbrlen (p, buf + size - p, &mbs); if ((size_t) -2 <= clen) return true; 

luego simplemente man mbrlen.

nlines_first_null y nlines

Inicializado como:

intmax_t nlines_first_null = -1; nlines = 0; 

de modo que cuando se encuentra un valor nulo 0 <= nlines_first_null se convierte en verdadero.

TODO cuándo puede nlines_first_null < nlines ¿alguna vez fue falso? Me volví perezoso.

POSIX

No define opciones binarias grep: busca un patrón en un archivo | pubs.opengroup.org , y GNU grep no lo documenta, por lo que RTFS es la única forma.

Comentarios

  • Explicación impresionante !
  • Tenga en cuenta que la verificación de UTF-8 válido solo ocurre en configuraciones regionales UTF-8. También tenga en cuenta que la verificación solo se realiza en la primera lectura del búfer del archivo, que para un archivo normal parece tener 32768 bytes en mi sistema, pero para una tubería o un conector puede ser tan pequeño como un byte. Compare (printf '\n\0y') | grep y con (printf '\n'; sleep 1; printf '\0y') | grep y, por ejemplo.
  • @St é phaneChazelas » Tenga en cuenta que la verificación de UTF-8 válido solo ocurre en configuraciones regionales UTF-8 «: ¿se refiere a la export LC_CTYPE='en_US.UTF-8' como en mi ejemplo, o algo más? Buf read: ejemplo asombroso, agregado a la respuesta. Obviamente, has leído la fuente más que yo, me recuerda a esos hacker koans » El estudiante se iluminó » 🙂
  • No ‘ tampoco miré en gran detalle, pero lo hizo muy recientemente
  • @CiroSantilli 巴拿馬 文件 六四 事件 法轮功 ¿contra qué versión de GNU grep probó?

Respuesta

Uno de mis archivos de texto fue visto de repente como binario por grep:

$ file foo.txt foo.txt: ISO-8859 text 

La solución fue convertirlo usando iconv:

iconv -t UTF-8 -f ISO-8859-1 foo.txt > foo_new.txt 

Comentarios

  • Esto también me pasó a mí. En particular, la causa fue un espacio sin ruptura codificado en ISO-8859-1, que tuve que reemplazar con un espacio regular para que grep buscara en el archivo.
  • grep 2.21 trata ISO -8859 archivos de texto como si fueran binarios, agregue export LC_ALL = C antes del comando grep.
  • @netawater ¡Gracias! Esto es por ejemplo el caso si tiene algo como M ü ller en un archivo de texto. Ese ‘ s 0xFC hexadecimal, por lo que fuera del rango que grep esperaría para utf8 (hasta 0x7F). Verifique con printf ‘ a \ x7F ‘ | grep ‘ a ‘ como describió Ciro anteriormente.

Respuesta

El archivo /etc/magic o /usr/share/misc/magic tiene una lista de secuencias que el comando file utiliza para determinar el tipo de archivo.

Tenga en cuenta que el binario puede ser simplemente una solución alternativa. A veces, los archivos con codificación extraña también se consideran binarios.

grep en Linux tiene algunas opciones para manejar archivos binarios como --binary-files o -U / --binary

Comentarios

Responder

Uno de mis alumnos tuvo este problema. Hay un error en grep en Cygwin. Si el archivo tiene caracteres que no son Ascii, grep y egrep lo ven como binario.

Comentarios

  • Eso suena como una característica, no un error.Especialmente dado que hay una opción de línea de comando para controlarlo (-a / –text)

Responder

Respondiendo realmente a la pregunta «¿Qué hace que grep considere que un archivo es binario?», Puede usar iconv:

$ iconv < myfile.java iconv: (stdin):267:70: cannot convert 

En mi caso había caracteres en español que aparecían correctamente en los editores de texto pero grep los consideraba binarios; iconv la salida me indicó los números de línea y columna de esos caracteres

En el caso de NUL caracteres, iconv los considerará normales y no imprimirá ese tipo de salida, por lo que este método no es adecuado

Respuesta

Tuve el mismo problema. Usé vi -b [filename] para ver los caracteres agregados. Encontré los caracteres de control ^@ y ^M. Luego, en vi, escriba :1,$s/^@//g para eliminar los ^@ caracteres. Repita este comando para ^M.

Advertencia: Para obtener los caracteres de control «azules», presione Ctrl + v y luego Ctrl + M o Ctrl + @ . Luego guarde y salga de vi.

Respuesta

También tuve este problema pero en mi caso fue causado cuando una línea coincidente es demasiado largo.

file myfile.txt myfile.txt: UTF-8 Unicode text, with very long lines 

grep se ejecutaría bien en todo el archivo con muchos patrones, pero cuando un patrón coincidía con un » línea muy larga » se detuvo con Binary file myfile.txt matches.

Agregar -a también resuelve este problema, pero el análisis previo del archivo para NULL u otros caracteres inválidos no tendría ningún efecto (no hay ninguno, de lo contrario grep no se completaría para otros patrones). ¡En este caso, la línea ofensiva tenía más de 25k caracteres!

Lo que no entiendo es por qué solo sucede cuando grep intenta devolver la línea y no cuando lo está procesando en busca de otros patrones.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *