grep recursivo no enumera coincidencias de algunos archivos
Estoy usando GNU grep 3.4 para encontrar scripts que contengan un patrón determinado. Por esto, llamo grep
recursivamente así
grep -rin . -e "pattern"
El patrón es solo una palabra, no una expresión regular. Lo extraño es que la salida no enumera las ocurrencias en algunos archivos que definitivamente contienen la cadena.
Intenté abrir estos archivos vim
y buscar allí usando /pattern
y encuentra el patrón. La codificación se muestra en vim
formato [dos:utf-8:]
. Cuando copio la línea y la escribo en un nuevo archivo, el grep
comando anterior lo enumera correctamente.
¿Por qué no grep
incluye el archivo original?
Respuestas
Grep (o al menos los mayores) no entienden UTF8. Por tanto, los caracteres compuestos, los puntos de separación de sílabas u otros datos invisibles pueden desalentar a grep.
Grep también se ve afectado por los valores de $LC_ALL, $LC_CTYPE y $ LANG.
Use vim para guardar algunas líneas alrededor de una palabra que grep no pudo encontrar y luego haga un hexadecimal de ese pequeño archivo de ejemplo. Probablemente verás por qué falló grep
También puede usar comandos vim ( ga
, g8
etc.) para examinar caracteres, pero un volcado hexadecimal puede ser más claro
Encontré el problema (con la ayuda de otra respuesta). Los archivos 'grep' no mostraron ningún resultado porque no estaban realmente utf-8
codificados, pero utf-16be
. Aprendí esto usando hexdump (créditos a @RedGrittyBrick):
hd file_for_which_grep_works_as_expected.txt
cedido
00000000 20 20 20 20 50 61 74 74 65 72 6e 0a | Pattern.|
0000000c
mientras
hd file_for_which_grep_fails.txt
regresó
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
Entonces, verificando la codificación con
file -i file_for_which_grep_fails.txt
lo identificó como text/plain; charset=utf-16be
.
No reconocí que los utf-8
mostrados por vim
eran en realidad la codificación del búfer , no la codificación del archivo . Ejecutar :set fileencoding
en vim
También se muestra correctamente fileencoding=utf-16
(que se encuentra aquíhttps://superuser.com/a/28783/1210682).
Entonces, el problema es que my grep
no funciona con utf-16
archivos codificados. Esto ya se ha descrito aquí:https://superuser.com/a/231471/1210682. Sin embargo, el remedio de convertir utf-16
archivos a utf-8
antes grep
no funciona cuando lo uso de forma recursiva, ya que no sé de antemano qué archivos pueden ser utf-8
y cuáles, utf-16
y estoy buscando en muchos archivos.
Existen diferentes soluciones, dos de las cuales voy a describir brevemente aquí:
Una solución rápida y sucia que funcionó para mí fue expandir el patrón de búsqueda para incluir uno que coincidiera con la
utf-16
versión y buscar uno de ambos patrones:grep -riPa . -e "pattern|p.a.t.t.e.r.n."
Por supuesto, esto es muy limitado en términos de posibles patrones.
Existen alternativas a Me
grep
gustaugrep
oripgrep
que (entre otras cosas) pueden manejarutf-16
archivos. Terminé usando loripgrep
que está disponible en los repositorios de paquetes estándar de Ubuntu desde 18.04 en adelante:rg -i "pattern"
Hay una gran discusión sobre alternativas aquí: https://stackoverflow.com/questions/3752913/grepping-binary-files-and-utf16, entre ellos un enfoque interesante que intenta convertir el patrón de búsqueda utf-16
y alimentarlo a grep
. Sin embargo, no pude hacer que funcionara.