grep ricorsivo non elenca le corrispondenze da alcuni file
Sto usando GNU grep 3.4 per trovare script che contengono un certo pattern. Per questo, chiamo grep
ricorsivamente 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 vim
e cercare lì usando /pattern
e trova il modello. La codifica viene visualizzata vim
come [dos:utf-8:]
. Quando copio la riga e la scrivo in un nuovo file, il grep
comando precedente lo elenca correttamente.
Perché non grep
elenca il file originale?
Risposte
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
, g8
ecc.) Per esaminare i caratteri, ma un dump esadecimale potrebbe essere più chiaro
Ho trovato il problema (con l'aiuto di un'altra risposta). I file 'grep' non mostravano alcun output perché non erano effettivamente utf-8
codificati, 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-8
mostrato da vim
era in realtà la codifica del buffer , non la codifica del file . Esecuzione :set fileencoding
in vim
anche visualizzate correttamente fileencoding=utf-16
(si trova quihttps://superuser.com/a/28783/1210682).
Quindi, il problema è che my grep
non funziona sui utf-16
file codificati. Questo è già stato descritto qui:https://superuser.com/a/231471/1210682. Tuttavia, il rimedio di convertire i utf-16
file in utf-8
prima grep
non funziona quando lo uso in modo ricorsivo, poiché non so in anticipo quali file possono essere utf-8
e quali utf-16
e sto cercando in molti file.
Esistono diverse soluzioni, due delle quali descriverò brevemente qui:
Una soluzione rapida e sporca che ha funzionato per me è stata espandere il modello di ricerca per includerne uno che corrispondesse alla
utf-16
versione 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.
Ci sono alternative a
grep
likeugrep
oripgrep
che (tra le altre cose) possono gestire iutf-16
file. Ho finito per usare quelloripgrep
disponibile 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-16
e lo alimenta a grep
. Tuttavia, non sono riuscito a farlo funzionare.