grep ricorsivo non elenca le corrispondenze da alcuni file

Aug 20 2020

Sto usando GNU grep 3.4 per trovare script che contengono un certo pattern. Per questo, chiamo grepricorsivamente in questo modo

grep -rin . -e "pattern" 

Lo schema è solo una parola, nessuna espressione regolare. La cosa strana è che l'output non elenca le occorrenze in alcuni file che contengono sicuramente la stringa.

Ho provato ad aprire questi file vime cercare lì usando /patterne trova il modello. La codifica viene visualizzata vimcome [dos:utf-8:]. Quando copio la riga e la scrivo in un nuovo file, il grepcomando precedente lo elenca correttamente.

Perché non grepelenca il file originale?

Risposte

1 RedGrittyBrick Aug 20 2020 at 20:08

Grep (o almeno quelli più vecchi) non capiscono UTF8. Quindi caratteri composti, punti di sillabazione o altri dati invisibili potrebbero scoraggiare grep.

Grep è anche influenzato dai valori di $LC_ALL, $LC_CTYPE e $ LANG.

Usa vim per salvare alcune righe attorno a una parola che grep non è riuscita a trovare, quindi fai un dump esadecimale di quel piccolo file di esempio. Probabilmente vedrai perché grep ha fallito

Puoi anche usare i comandi vim ( ga, g8ecc.) Per esaminare i caratteri, ma un dump esadecimale potrebbe essere più chiaro

1 buddemat Aug 20 2020 at 22:28

Ho trovato il problema (con l'aiuto di un'altra risposta). I file 'grep' non mostravano alcun output perché non erano effettivamente utf-8codificati, ma utf-16be. L'ho imparato usando hexdump (crediti a @RedGrittyBrick):

hd file_for_which_grep_works_as_expected.txt

ceduto

00000000  20 20 20 20 50 61 74 74  65 72 6e 0a              |    Pattern.|
0000000c

mentre

hd file_for_which_grep_fails.txt

restituito

00000000  fe ff 00 50 00 61 00 74  00 74 00 65 00 72 00 6e  |...P.a.t.t.e.r.n|
00000010  00 0a                                             |..|
00000012

Quindi, ricontrollando la codifica con

file -i file_for_which_grep_fails.txt

identificato come text/plain; charset=utf-16be.

Non sono riuscito a riconoscere che quello utf-8mostrato da vimera in realtà la codifica del buffer , non la codifica del file . Esecuzione :set fileencodingin vimanche visualizzate correttamente fileencoding=utf-16(si trova quihttps://superuser.com/a/28783/1210682).

Quindi, il problema è che my grepnon funziona sui utf-16file codificati. Questo è già stato descritto qui:https://superuser.com/a/231471/1210682. Tuttavia, il rimedio di convertire i utf-16file in utf-8prima grepnon funziona quando lo uso in modo ricorsivo, poiché non so in anticipo quali file possono essere utf-8e quali utf-16e sto cercando in molti file.

Esistono diverse soluzioni, due delle quali descriverò brevemente qui:

  1. Una soluzione rapida e sporca che ha funzionato per me è stata espandere il modello di ricerca per includerne uno che corrispondesse alla utf-16versione e cercare uno di entrambi i modelli:

    grep -riPa . -e "pattern|p.a.t.t.e.r.n."
    

    Questo è ovviamente molto limitato in termini di possibili modelli.

  2. Ci sono alternative a greplike ugrepo ripgrepche (tra le altre cose) possono gestire i utf-16file. Ho finito per usare quello ripgrepdisponibile nei repository di pacchetti standard di Ubuntu dalla 18.04 in poi:

    rg -i "pattern"  
    

C'è una grande discussione sulle alternative qui: https://stackoverflow.com/questions/3752913/grepping-binary-files-and-utf16, tra questi un approccio interessante che tenta di convertire il modello di ricerca in utf-16e lo alimenta a grep. Tuttavia, non sono riuscito a farlo funzionare.