¿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?

Daniel YC Lin
fuente
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
serverfault.com/questions/328101/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

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.

vielmetti
fuente
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
110
grep -a

No puede ser más simple que eso.

James Selvakumar
fuente
3
esto es lo mismo grep --textque paxdiablo ha mencionado 2 años antes
user829755
4
Sí, excepto que esto no funcionará en OSX a menos que haga lo siguiente:LC_ALL="C" grep -a
Chris Stratton
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
paxdiablo
fuente
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
malhumorado
fuente
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.

AB
fuente
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

Steven Penny
fuente
5

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

Kevin Buchs
fuente
3

Como ya dijo James Selvakumar, grep -afunciona. -a o --text obliga a Grep a manejar el flujo de entrada como texto. Ver página de manual http://unixhelp.ed.ac.uk/CGI/man-cgi?grep

tratar

cat test.log | grep -a somestring
DerKnorr
fuente
2

tu puedes hacer

strings test.log | grep -i

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

Mrid
fuente
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).

MattCollW
fuente
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.

Muurder
fuente