Come eseguire il grep di un file di testo che contiene alcuni dati binari?


122

grep restituisce

Il file binario test.log corrisponde

Per esempio

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

Vorrei che il risultato mostrasse riga1 e riga3 (totale due righe).

È possibile trconvertire i dati non stampabili in dati leggibili, per far funzionare di nuovo grep?


Si noti che esiste un programma che filtra i caratteri binari da un file binario e mantiene solo i caratteri di testo (leggibili). Qui: soft.tahionic.com/download-words_extractor/index.html
InTheNameOfScience

Mi scusi, ma ... non ti manca -eil echocomando?
Sopalajo de Arrierez

Se usi 'zsh', va bene senza -e. Se usi "bash", dovresti aggiungere "-e".
Daniel YC Lin

Risposte:


67

È possibile eseguire il file di dati cat -v, ad es

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

che potrebbe essere ulteriormente post-elaborato per rimuovere la spazzatura; questo è molto simile alla tua domanda sull'utilizzo trper l'attività.


5
Ho risolto il mio problema. Grazie! Ecco cosa man catdice di -v:-v, --show-nonprinting use ^ and M- notation, except for LFD and TAB
tommy.carstensen

Nota che questo funziona anche in una pipeline. Ad esempioset | cat -v | grep variable
funroll

1
Perché usarlo se grep --text funziona? Questo sembra molto più complesso.
Michael Haefele

grep --textnon sempre funziona; rispetta CTRL + D come terminatore di file. Quindi, se lo hai nel tuo file binario, grep uscirà presto.
Tommy il

110
grep -a

Non può essere più semplice di così.


3
questo è lo stesso di grep --textcui paxdiablo ha menzionato 2 anni prima
user829755

4
Sì, tranne per il fatto che non funzionerà su OSX a meno che tu non esegua le seguenti operazioni:LC_ALL="C" grep -a
Chris Stratton

91

Un modo è quello di trattare semplicemente i file binari come testo comunque, grep --textma questo potrebbe comportare l'invio di informazioni binarie al tuo terminale. Non è proprio una buona idea se stai utilizzando un terminale che interpreta il flusso di output (come VT / DEC o molti altri).

In alternativa, puoi inviare il tuo file trcon il seguente comando:

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

Questo cambierà qualsiasi cosa minore di uno spazio (eccetto la nuova riga) e qualsiasi cosa maggiore di 126, in un .carattere, lasciando solo gli stampabili.


Se vuoi che ogni carattere "illegale" venga sostituito da uno diverso, puoi usare qualcosa di simile al seguente programma C, un classico filtro di input standard:

#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;
}

Questo ti darà {{NN}}, dov'è NNil codice esadecimale per il personaggio. Puoi semplicemente regolare il printfper qualunque stile di output desideri.

Puoi vedere quel programma in azione qui, dove:

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

Questo metodo mappa tutti i caratteri binari nello stesso "." simbolo. C'è un altro metodo per associarli a simboli leggibili?
Daniel YC Lin

Certo, puoi eseguirlo tramite un programma di filtro diverso, uno dei quali ho fornito in un aggiornamento.
paxdiablo

1
Penso tr '[:cntrl:] '.'sia meglio. E dovrebbe essere \000-\010\013\014\016-\037\177-\377'nella tua sintassi tr.
Daniel YC Lin

2
Dopo il test, tr '[\000-\010\013\014\016-\037\177-\377]' '_'praticabile, il cntrl non è adatto al mio caso.
Daniel YC Lin

2
Puoi salvare il catpassaggio collegandoti grep --textatr non viceversa. Ciò consente anche di grep più file e mantenere il riferimento al nome del file nell'output.
aaaantoine

33

È possibile utilizzare "stringhe" per estrarre stringhe da un file binario, ad esempio

strings binary.file | grep foo

Ha funzionato bene per me poiché la fonte era un registro di debug con UID su ogni riga. Grazie.
mbrownnyc

ha funzionato bene anche per me. Grazie per la tua risposta. Mi ha salvato la giornata :)
Shekhar

2
Apprezzo la risposta di @paxdiablo, ma per una risposta rapida e per andare avanti con il lavoro non puoi criticare.
Wil

Ho provato a usare la soluzione paxdiablo, ma non mi ha dato nessuno dei risultati che mi aspettavo. @moodywoody la tua soluzione è veloce, semplice e fornisce esattamente ciò di cui avevo bisogno!
justinhartman

20

Puoi forzare grep a guardare i file binari con:

grep --binary-files=text

Potresti anche voler aggiungere -o( --only-matching) in modo da non ottenere tonnellate di incomprensioni binarie che rovinerebbero il tuo terminale.


potrebbe produrre spazzatura binaria, che può avere effetti collaterali spiacevoli se l'output è un terminale e se il driver del terminale ne interpreta alcuni come comandi.
Daniel YC Lin

Se usi --only-matchinge la tua regex non corrisponde a dati binari arbitrari, non avrai problemi.
AB

se l'espressione regolare è 'first. * end' e i dati binari contengono nel pattern '. *', non può correggere il processo per la mia post-elaborazione. Comunque grazie.
Daniel YC Lin

16

A partire da Grep 2.21, i file binari vengono trattati in modo diverso :

Durante la ricerca di dati binari, grep ora può trattare i byte non di testo come terminatori di riga. Questo può aumentare significativamente le prestazioni.

Quindi quello che succede ora è che con i dati binari, tutti i byte non di testo (compresi i caratteri di ritorno a capo) vengono trattati come terminatori di riga. Se desideri modificare questo comportamento, puoi:

  • utilizzare --text. Ciò garantirà che solo le nuove righe siano terminatori di riga

  • utilizzare --null-data. Ciò garantirà che solo i byte nulli siano terminatori di riga


5

grep -a costringerà grep a cercare e produrre da un file che grep pensa sia binario. grep -a re test.log



2

tu puoi fare

strings test.log | grep -i

questo convertirà l'output come stringa leggibile in grep.


0

Puoi anche provare lo strumento Word Extractor . Word Extractor può essere utilizzato con qualsiasi file nel computer per separare le stringhe che contengono testo / parole umane dal codice binario (applicazioni exe, DLL).


Nel mio caso, non ho bisogno di estrattore di parole, ho bisogno di mantenere il numero di riga.
Daniel YC Lin

0

Ecco cosa ho usato in un sistema che non aveva il comando "stringhe" installato

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

Questo stampa il testo e rimuove i caratteri non stampabili in un colpo solo, a differenza di "cat -v filename" che richiede un po 'di post-elaborazione per rimuovere le cose indesiderate. Nota che alcuni dei dati binari potrebbero essere stampabili, quindi avrai ancora un po 'di incomprensioni tra le cose buone. Penso che le stringhe rimuovano anche questo incomprensibile se puoi usarlo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.