¿Una forma elegante de buscar archivos UTF-8 con BOM?

94

Para fines de depuración, necesito buscar de forma recursiva en un directorio todos los archivos que comienzan con una marca de orden de bytes (BOM) UTF-8. Mi solución actual es un script de shell simple:

find -type f |
while read file
do
    if [ "`head -c 3 -- "$file"`" == $'\xef\xbb\xbf' ]
    then
        echo "found BOM in: $file"
    fi
done

O, si prefiere frases breves e ilegibles:

find -type f|while read file;do [ "`head -c3 -- "$file"`" == $'\xef\xbb\xbf' ] && echo "found BOM in: $file";done

No funciona con nombres de archivo que contienen un salto de línea, pero de todos modos no se esperan tales archivos.

¿Existe alguna solución más corta o más elegante?

¿Hay editores de texto o macros interesantes para editores de texto?

vog
fuente

Respuestas:

166

¿Qué pasa con este comando simple que no solo encuentra sino que borra la desagradable lista de materiales? :)

find . -type f -exec sed '1s/^\xEF\xBB\xBF//' -i {} \;

Me encanta "encontrar" :)

Advertencia Lo anterior modificará los archivos binarios que contienen esos tres caracteres.

Si solo desea mostrar archivos BOM, use este:

grep -rl $'\xEF\xBB\xBF' .
Denis
fuente
9
Detecta PDF incorrectamente con un marcador BOM ... eso es porque busca en todo el documento, no solo en la primera línea
Olivier Refalo
1
O con ack: "ack '\ xEF \ xBB \ xBF'"
Smar
5
cambie el comando sed para agregar un 1 antes de la 's' inicial para que solo se aplique a la primera línea
Ben Combee
27
Úselo grep -rlI $'\xEF\xBB\xBF' .para ignorar archivos binarios.
dbernard
1
Detecta y modifica JPG y otros archivos binarios, como ya se dijo.
Jehy
41

La mejor y más sencilla forma de hacer esto en Windows:

Total Commander → ir al directorio raíz del proyecto → buscar archivos ( Alt+ F7) → tipos de archivo *. * → Buscar texto "EF BB BF" → marcar la casilla de verificación 'Hex' → buscar

Y obtienes la lista :)

Jan Przybylo
fuente
4
Agradable, especialmente el uso de mi comandante Total favorito desde hace mucho tiempo, pero desafortunadamente esto tiene el mismo problema que muchos otros: busca todos los bytes en un archivo, se reportan tantas imágenes, etc. Esto se puede mejorar ligeramente usando RegEx en lugar de Hex y buscando "^ \ xEF \ xBB \ xBF", lo que eliminará muchas imágenes, pero aún tiene archivos que tienen la lista de materiales a la mitad del archivo (aunque debería haber pocos) y, por supuesto, cualquier archivo binario que tenga un código de caracteres de nueva línea ascii justo antes de la lista de materiales. Aún así, todas las imágenes desaparecieron en mi búsqueda de prueba.
Legolas
13
find . -type f -print0 | xargs -0r awk '
    /^\xEF\xBB\xBF/ {print FILENAME}
    {nextfile}'

La mayoría de las soluciones proporcionadas anteriormente prueban más que la primera línea del archivo, incluso si algunas (como la solución de Marcus) luego filtran los resultados. Esta solución solo prueba la primera línea de cada archivo, por lo que debería ser un poco más rápida.

Aron Griffis
fuente
1
Got está trabajando con lo siguiente en Linux (RHEL6) -find . -type f -print0 | xargs -0 awk '/^\xEF\xBB\xBF/ {print FILENAME} {nextfile}'
Olivier Refalo
¿Cómo tengo que modificar su código para arreglar estos archivos después de que fueron encontrados?
Negro
7

Si acepta algunos falsos positivos (en caso de que haya archivos que no sean de texto, o en el caso poco probable de que haya un ZWNBSP en medio de un archivo), puede usar grep:

fgrep -rl `echo -ne '\xef\xbb\xbf'` .
CesarB
fuente
5

Usaría algo como:

grep -orHbm1 "^`echo -ne '\xef\xbb\xbf'`" . | sed '/:0:/!d;s/:0:.*//'

Lo que garantizará que la lista de materiales se produzca a partir del primer byte del archivo.

Marcus Griep
fuente
5

Puede usar greppara encontrarlos y Perl para eliminarlos así:

grep -rl $'\xEF\xBB\xBF' . | xargs perl -i -pe 's{\xEF\xBB\xBF}{}'
teoría
fuente
Este funcionó para mí, la respuesta aceptada no lo hizo (estoy en una Mac)
mjsarfatti
4

Para un usuario de Windows, vea esto (buen script PHP para encontrarlo BOMen su proyecto).

julien
fuente
El sitio web vinculado muestra: "Sitio web sin conexión, sin versión en caché disponible".
vog
El mismo script también está disponible en github: github.com/emrahgunduz/BomCleaner
emrahgunduz
Gracias amigo, tu respuesta me salvó el día.
Krunal Panchal
Y un Buscador de BOM: github.com/svn2github/wikia/blob/master/extensions/FCKeditor/… (en caso de que a alguien no le guste la limpieza 'automática', o simplemente quiera encontrar los archivos con BOM)
meloniq
3

Una solución exagerada para esto es phptags(no la viherramienta con el mismo nombre), que busca específicamente scripts PHP:

phptags --warn ./

Producirá algo como:

./invalid.php: TRAILING whitespace ("?>\n")
./invalid.php: UTF-8 BOM alone ("\xEF\xBB\xBF")

Y el --whitespacemodo solucionará automáticamente dichos problemas (de forma recursiva, pero afirma que solo reescribe scripts .php).

mario
fuente
2
find -type f -print0 | xargs -0 grep -l `printf '^\xef\xbb\xbf'` | sed 's/^/found BOM in: /'
  • find -print0 pone un \ 0 nulo entre cada nombre de archivo en lugar de usar nuevas líneas
  • xargs -0 espera argumentos separados por nulos en lugar de separados por líneas
  • grep -l enumera los archivos que coinciden con la expresión regular
  • La expresión regular ^\xeff\xbb\xbfno es del todo correcta, ya que coincidirá con archivos UTF-8 no BOMed si tienen espacios de ancho cero al comienzo de una línea
Jonathan Wright
fuente
Todavía necesita un "cabezal 1" en la tubería antes del grep
MSalters
2

Usé esto para corregir solo archivos JavaScript:

find . -iname *.js -type f -exec sed 's/^\xEF\xBB\xBF//' -i.bak {} \; -exec rm {}.bak \;
Refineo
fuente
0

Si está buscando archivos UTF, el comando de archivo funciona. Le dirá cuál es la codificación del archivo. Si hay algún carácter que no sea ASCII, aparecerá con UTF.

file *.php | grep UTF

Sin embargo, eso no funcionará de forma recursiva. Probablemente pueda configurar algún comando elegante para hacerlo recursivo, pero solo busqué cada nivel individualmente como el siguiente, hasta que me quedé sin niveles.

file */*.php | grep UTF
Mike Dotterer
fuente