¿Cómo grep de un archivo de texto que contiene algunos datos binarios?


122

devuelve grep

Coincidencias de archivo binario test.log

Por ejemplo

echo    "line1 re \x00\r\nline2\r\nline3 re\r\n" > test.log  # in zsh
echo -e "line1 re \x00\r\nline2\r\nline3 re\r\n" > test.log  # in bash
grep re test.log

Deseo que el resultado muestre la línea 1 y la línea 3 (dos líneas en total).

¿Es posible trconvertir los datos no imprimibles en datos legibles para que grep vuelva a funcionar?


Tenga en cuenta que existe un programa que filtra los caracteres binarios de un archivo binario y mantiene solo los caracteres de texto (legibles). Aquí: soft.tahionic.com/download-words_extractor/index.html
InTheNameOfScience

Disculpe, pero ... ¿no falta -een el echocomando?
Sopalajo de Arrierez

Si usa 'zsh', está bien sin -e. Si usa 'bash', debe agregar '-e'.
Daniel YC Lin

Respuestas:


67

Puede ejecutar el archivo de datos cat -v, por ejemplo

$ cat -v tmp/test.log | grep re
line1 re ^@^M
line3 re^M

que luego podría procesarse posteriormente para eliminar la basura; esto es más análogo a su consulta sobre el uso trpara la tarea.


5
Resolvió mi problema. ¡Gracias! man cat-v-v, --show-nonprinting use ^ and M- notation, except for LFD and TAB
Esto

Tenga en cuenta que esto también funciona en una tubería. Por ejemploset | cat -v | grep variable
funroll

1
¿Por qué usar esto si grep --text funciona? Esto parece mucho más complejo.
Michael Haefele

grep --textno siempre funciona; respeta CTRL + D como terminador de archivos. Entonces, si tiene eso en su archivo binario, grep saldrá temprano.
Tommy


91

Una forma es simplemente tratar los archivos binarios como texto de todos modos, grep --textpero esto puede resultar en que se envíe información binaria a su terminal. Eso no es realmente una buena idea si está ejecutando un terminal que interpreta el flujo de salida (como VT / DEC o muchos otros).

Alternativamente, puede enviar su archivo trcon el siguiente comando:

tr '[\000-\011\013-\037\177-\377]' '.' <test.log | grep whatever

Esto cambiará cualquier carácter menor que un espacio (excepto una nueva línea) y algo mayor que 126, en un .carácter, dejando solo los imprimibles.


Si desea que cada carácter "ilegal" sea reemplazado por uno diferente, puede usar algo como el siguiente programa en C, un filtro de entrada estándar clásico:

#include<stdio.h>
int main (void) {
    int ch;
    while ((ch = getchar()) != EOF) {
        if ((ch == '\n') || ((ch >= ' ') && (ch <= '~'))) {
            putchar (ch);
        } else {
            printf ("{{%02x}}", ch);
        }
    }
    return 0;
}

Esto le dará {{NN}}dónde NNestá el código hexadecimal del personaje. Simplemente puede ajustar el printfpara cualquier estilo de salida que desee.

Puede ver ese programa en acción aquí, donde:

pax$ printf 'Hello,\tBob\nGoodbye, Bob\n' | ./filterProg
Hello,{{09}}Bob
Goodbye, Bob

Este método mapea todos los caracteres binarios en el mismo '.' símbolo. ¿Existe otro método que los asigne a símbolos legibles?
Daniel YC Lin

Claro, puede ejecutarlo a través de un programa de filtro diferente, uno de los cuales he proporcionado en una actualización.
paxdiablo

1
Creo que tr '[:cntrl:] '.'es mejor. Y debería estar \000-\010\013\014\016-\037\177-\377'en su sintaxis tr.
Daniel YC Lin

2
Después de la prueba, tr '[\000-\010\013\014\016-\037\177-\377]' '_'viable, el cntrl no es adecuado para mi caso.
Daniel YC Lin

2
Puede guardar el catpaso entubando grep --texten trlugar de viceversa. Esto también le permite grep de varios archivos y mantener la referencia del nombre del archivo en la salida.
aaaantoine

33

Puede utilizar "cadenas" para extraer cadenas de un archivo binario, por ejemplo

strings binary.file | grep foo

Me funcionó bien ya que la fuente era un registro de depuración con UID en cada línea. Gracias.
mbrownnyc

funcionó bien para mí también. Gracias por tu respuesta. Salvó mi día :)
Shekhar

2
Aprecio la respuesta de @paxdiablo, pero para una respuesta rápida y para continuar con el trabajo, no puede fallar.
Sábado

Intenté usar la solución paxdiablo, sin embargo, no me dio ninguno de los resultados que esperaba. @moodywoody, ¡su solución es rápida, simple y produce exactamente lo que necesitaba!
justinhartman

20

Puede forzar a grep a mirar archivos binarios con:

grep --binary-files=text

Es posible que también desee agregar -o( --only-matching) para no obtener toneladas de galimatías binarias que arruinarán su terminal.


puede generar basura binaria, que puede tener efectos secundarios desagradables si la salida es una terminal y si el controlador de terminal interpreta parte de ella como comandos.
Daniel YC Lin

Si usa --only-matching, y su expresión regular no coincide con datos binarios arbitrarios, no tendrá ningún problema.
AB

si la expresión regular es 'first. * end' y los datos binarios contienen un patrón '. *', no puede corregir el proceso para mi procesamiento posterior. Gracias de todos modos.
Daniel YC Lin

16

A partir de Grep 2.21, los archivos binarios se tratan de manera diferente :

Al buscar datos binarios, grep ahora puede tratar los bytes que no son de texto como terminadores de línea. Esto puede mejorar el rendimiento de manera significativa.

Entonces, lo que sucede ahora es que con los datos binarios, todos los bytes que no son de texto (incluidas las nuevas líneas) se tratan como terminadores de línea. Si desea cambiar este comportamiento, puede:

  • utilizar --text . Esto asegurará que solo las nuevas líneas sean terminadores de línea

  • utilizar --null-data. Esto asegurará que solo los bytes nulos sean terminadores de línea


5

grep -a forzará a grep a buscar y generar desde un archivo que grep piensa que es binario. grep -a re test.log



2

tu puedes hacer

strings test.log | grep -i

esto convertirá la salida como una cadena legible a grep.


0

También puede probar la herramienta Word Extractor . Word Extractor se puede usar con cualquier archivo en su computadora para separar las cadenas que contienen texto / palabras humanas del código binario (aplicaciones exe, DLL).


En mi caso, no necesito un extractor de palabras, necesito mantener el número de línea.
Daniel YC Lin

0

Esto es lo que usé en un sistema que no tenía el comando "strings" instalado

cat yourfilename | tr -cd "[:print:]"

Esto imprime el texto y elimina los caracteres no imprimibles de una sola vez, a diferencia de "cat -v filename", que requiere un procesamiento posterior para eliminar elementos no deseados. Tenga en cuenta que algunos de los datos binarios pueden imprimirse, por lo que aún obtendrá algunos galimatías entre las cosas buenas. Creo que las cuerdas también eliminan este galimatías si puedes usar eso.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.