Ho alcuni dump del database da un sistema Windows sulla mia macchina. Sono file di testo. Sto usando cygwin per eseguire grep. Questi sembrano essere file di testo semplice; li apro con editor di testo come blocco note e wordpad e sembrano leggibili. Tuttavia, quando eseguo grep su di essi, verrà visualizzato binary file foo.txt matches.

Ho notato che i file contengono alcuni caratteri ascii NUL, che credo siano artefatti dal dump del database.

Quindi cosa fa sì che grep consideri questi file come binari? Il carattere NUL? Cè un flag nel filesystem? Cosa devo cambiare per ottenere grep mostrarmi le corrispondenze di riga?

Commenti

  • --null-data può essere utile se NUL è il delimitatore.

Risposta

Se è presente un NUL in qualsiasi punto del file, grep lo considererà un file binario.

Potrebbe essere una soluzione alternativa come questa cat file | tr -d "\000" | yourgrep per eliminare prima tutto nullo e quindi per cercare nel file.

Commenti

  • … oppure usa -a / --text, almeno con GNU grep.
  • @derobert: in realtà, su alcuni sistemi (meno recenti) grep vede le righe, ma il suo output troncerà ogni riga corrispondente alla prima NUL (probabilmente perché chiama C ‘ s printf e gli fornisce la riga corrispondente?). Su un tale sistema, un grep cmd .sh_history restituirà tante righe vuote quante sono le righe corrispondenti a ‘ cmd ‘, poiché ogni riga di sh_history ha un formato specifico con un NUL allinizio di ogni riga. (ma il tuo commento ” almeno su GNU grep ” probabilmente si avvera. Io non ‘ ne ho uno a portata di mano in questo momento da testare, ma mi aspetto che lo gestiscano bene)
  • La presenza di un carattere NUL è lunico criterio? Ne dubito. ‘ è probabilmente più intelligente di così. Tutto ciò che non rientra nellintervallo Ascii 32-126 sarebbe la mia ipotesi, ma ‘ avremmo dovuto guardare il codice sorgente per essere sicuri.
  • Le mie informazioni erano dalla pagina man della specifica istanza grep. Il tuo commento sullimplementazione è valido, la fonte supera i documenti.
  • Avevo un file che grep su cygwin considerava binario perché aveva un trattino lungo (0x96) invece di un normale trattino ASCII / meno (0x2d). Immagino che questa risposta abbia risolto il problema dellOP ‘, ma sembra che sia incompleto.

Risposta

grep -a ha funzionato per me:

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

Commenti

  • Questa è la risposta migliore e meno costosa IMO.
  • Ma non conforme a POSIX
  • Ti dispiacerebbe spiegare perché non lo è? Sarebbe bene chiarirlo, per tutti noi che troviamo questa risposta come unopzione. Grazie :).
  • Ciao, ‘ sono venuto qui una SECONDA volta per imparare di nuovo questo LOL. Un accento francese (diacritico) nel testo faceva barf a grep

Answer

Puoi usare strings utilità per estrarre il contenuto di testo da qualsiasi file e quindi reindirizzarlo tramite grep, in questo modo: strings file | grep pattern.

Commenti

  • Ideale per grepping file di log che potrebbero essere parzialmente danneggiati
  • sì, a volte logging binario misto succede anche. Questo va bene.

Risposta

GNU grep 2.24 RTFS

Conclusione: solo 2 e 2 casi:

  • NUL, ad es printf "a\0" | grep "a"

  • errore di codifica in base a C99 mbrlen(), ad esempio:

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

    perché \x80 non può essere il primo byte di un punto Unicode UTF-8: UTF-8 – Descrizione | en.wikipedia.org

Inoltre, come menzionato da Stéphane Chazelas Ciò che fa considerare grep un file da essere binario? | Unix & Linux Stack Exchange , questi controlli vengono eseguiti solo fino alla prima lettura del buffer di lunghezza TODO.

Solo fino al primo buffer di lettura

Quindi, se si verifica un errore NUL o di codifica nel mezzo di un file molto grande, potrebbe essere grepped comunque.

Immagino che questo sia per motivi di prestazioni.

Ad esempio: questo stampa la riga:

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

ma questo non:

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

La dimensione effettiva del buffer dipende da come viene letto il file. Per esempio.confronta:

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

Con sleep, la prima riga viene passata a grep anche se è solo 1 byte lungo perché il processo va in sospensione e la seconda lettura non controlla se il file è binario.

RTFS

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

Trova dove è codificato il messaggio di errore stderr:

git grep "Binary file" 

Ci porta 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); 

Se quelle variabili erano ben denominate, in pratica siamo giunti alla conclusione.

encoding_error_output

Grepping rapido per encoding_error_output mostra che lunico percorso di codice che può modificarlo passa attraverso buf_has_encoding_errors:

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

quindi solo man mbrlen.

nlines_first_null e nlines

Inizializzato come:

intmax_t nlines_first_null = -1; nlines = 0; 

così quando viene trovato un valore nullo 0 <= nlines_first_null diventa vero.

TODO quando è possibile nlines_first_null < nlines mai essere falso? Sono diventato pigro.

POSIX

Non definisce le opzioni binarie grep – cerca un pattern | pubs.opengroup.org e GNU grep non lo documenta, quindi RTFS è lunico modo.

Commenti

  • Spiegazione impressionante !
  • Nota che il controllo per UTF-8 valido avviene solo nelle versioni locali UTF-8. Si noti inoltre che il controllo viene eseguito solo sul primo buffer letto dal file che per un file normale sembra essere 32768 byte sul mio sistema, ma per una pipe o un socket può essere piccolo come un byte. Confronta (printf '\n\0y') | grep y con (printf '\n'; sleep 1; printf '\0y') | grep y ad esempio.
  • @St é phaneChazelas ” Tieni presente che il controllo di UTF-8 valido avviene solo nelle versioni locali UTF-8 “: intendi per export LC_CTYPE='en_US.UTF-8' come nel mio esempio o qualcosaltro? Buf letto: esempio straordinario, aggiunto alla risposta. Ovviamente hai letto la fonte più di me, mi ricorda quei koan degli hacker ” Lo studente era illuminato ” 🙂
  • ‘ non ho nemmeno esaminato i dettagli, ma ha fatto molto di recente
  • @CiroSantilli 巴拿馬 文件 六四 事件 法轮功 con quale versione di GNU grep hai testato?

Risposta

Uno dei miei file di testo è stato improvvisamente visto come binario da grep:

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

La soluzione era convertirlo utilizzando iconv:

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

Commenti

  • È successo anche a me. In particolare, la causa era uno spazio unificatore codificato ISO-8859-1, che ho dovuto sostituire con uno spazio normale per fare in modo che grep cercasse nel file.
  • grep 2.21 tratta ISO -8859 file di testo come se fossero binari, aggiungi export LC_ALL = C prima del comando grep.
  • @netawater Grazie! Questo è ad es. il caso se hai qualcosa come M ü ller in un file di testo. Questo ‘ è 0xFC esadecimale, quindi al di fuori dellintervallo che grep si aspetta per utf8 (fino a 0x7F). Verifica con printf ‘ a \ x7F ‘ | grep ‘ a ‘ come Ciro ha descritto sopra.

Risposta

Il file /etc/magic o /usr/share/misc/magic ha un elenco di sequenze che il comando file utilizza per determinare il tipo di file.

Nota che il binario potrebbe essere solo una soluzione di riserva. A volte anche i file con una codifica strana sono considerati binari.

grep su Linux ha alcune opzioni per gestire i file binari come --binary-files o -U / --binary

Commenti

Risposta

Uno dei miei studenti ha riscontrato questo problema. È presente un bug in grep in Cygwin. Se il file contiene caratteri non Ascii, grep e egrep lo vedono come binario.

Commenti

  • Sembra una funzionalità, non un bug.Soprattutto dato che esiste unopzione della riga di comando per controllarlo (-a / –text)

Answer

In realtà rispondendo alla domanda “Cosa fa considerare grep un file binario?”, Puoi utilizzare iconv:

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

Nel mio caso cerano caratteri spagnoli che venivano visualizzati correttamente negli editor di testo ma grep li considerava binari; iconv mi ha indicato i numeri di riga e di colonna di quei caratteri

Nel caso di NUL caratteri, iconv li considererà normali e non stamperà quel tipo di output quindi questo metodo non è adatto

Risposta

Ho avuto lo stesso problema. Ho utilizzato vi -b [filename] per vedere i caratteri aggiunti. Ho trovato i caratteri di controllo ^@ e ^M. Quindi in vi digita :1,$s/^@//g per rimuovere i caratteri ^@. Ripeti questo comando per ^M.

Avviso: per ottenere i caratteri di controllo “blu”, premere Ctrl + v quindi Ctrl + M o Ctrl + @ . Quindi salva ed esci da vi.

Risposta

Anchio ho avuto questo problema ma nel mio caso è stato causato da una riga corrispondente troppo lungo.

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

grep eseguiva lintero file senza problemi con molti pattern, ma quando un pattern corrisponde a un ” riga molto lunga ” si è interrotta con Binary file myfile.txt matches.

Anche laggiunta di -a risolve questo problema, ma la pre-analisi del file per NULL o altri caratteri non validi non avrebbe alcun effetto (non ce ne sono, altrimenti grep non sarebbe completo per altri pattern). In questo caso la riga incriminata aveva più di 25.000 caratteri!

Quello che non capisco è perché accade solo quando grep cerca di restituire la riga e non quando lo sta elaborando cercando altri modelli.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *