¿Cómo puedo eliminar la lista de materiales de un archivo UTF-8?

64

Tengo un archivo en codificación UTF-8 con BOM y quiero eliminar la BOM. ¿Hay alguna herramienta de línea de comandos de Linux para eliminar la lista de materiales del archivo?

$ file test.xml
test.xml:  XML 1.0 document, UTF-8 Unicode (with BOM) text, with very long lines
m13r
fuente
1
Hice una herramienta muy simple para hacer eso hace unos meses: oskog97.com/read/?path=/small-scripts/killbom&referer=/… Podría valer la pena instalar algo así en / usr / local / bin si tiene muchos archivos codificados UTF-8 con BOM.
Oskar Skog

Respuestas:

76

Si no está seguro de si el archivo contiene una lista de materiales UTF-8, esto (suponiendo la implementación de GNU de sed) eliminará la lista de materiales si existe, o no hará cambios si no es así.

sed '1s/^\xEF\xBB\xBF//' < orig.txt > new.txt

También puede sobrescribir el archivo existente con la -iopción:

sed -i '1s/^\xEF\xBB\xBF//' orig.txt
CSM
fuente
44
Esto puede no funcionar en un entorno local utf8, pero anteponer una anulación de entorno local a c o posix siempre funcionará.
hildred
3
@hildred Lo probé con la en_US.UTF-8configuración regional y funcionó. ¿Cuándo fallará?
m13r
2
@ m13r, depende de la versión de sed y las opciones de compilación. En el caso de falla, una versión muy nueva de sed con clases de caracteres Unicode traerá la secuencia de tres bytes como un solo carácter que no coincide con la secuencia de tres caracteres. Sin embargo, en tal caso puede hacer una coincidencia de caracteres de dieciséis bits. Sin embargo, esta es una característica nueva y no está universalmente presente. Si desea probar, le recomiendo compilar la última versión.
hildred
44
Para arreglarlo para que funcione con un sed habilitado para Unicode, haga LC_ALL = C sed '1s / ^ \ xEF \ xBB \ xBF //'
Joshua
1
@mazunki, 1s/significa solo buscar en la primera línea; otras líneas no se ven afectadas. Los ^medios solo coinciden al comienzo de la (primera) línea. \xEF\xBB\xBFes la lista de materiales UTF-8 (cadena hexadecimal escapada). //significa reemplazar con nada. Podría haber agregado 1al final (for 1s/^xEF\xBB\xBF//1), lo que significaría que solo coincida con la primera aparición del patrón en la línea. Pero como la búsqueda está anclada ^, esto no hará ninguna diferencia. Si el archivo no tiene la lista de materiales al comienzo de la primera línea, el patrón no coincidirá y, por lo tanto, no se realiza ningún cambio.
CSM
64

Una lista de materiales no tiene sentido en UTF-8. Por lo general, se agregan por error por software falso en sistemas operativos Microsoft.

dos2unix lo eliminará y también se encargará de otras idiosincrasias de archivos de texto de Windows.

dos2unix test.xml
Stéphane Chazelas
fuente
17
Estoy de acuerdo en que una lista de materiales codificada UTF-8 no tiene sentido, pero créanlo o no, hay muchas personas que piensan que es una gran idea que ayuda a diferenciar UTF-8 de otras codificaciones de 8 bits. Entonces es cuestión de gustos. El Bloc de notas de Windows agrega una lista de materiales a propósito.
Johan Myréen
17
¿Qué importa si tiene sentido o no, cuando el contexto es solo una pregunta sobre cómo eliminarlo? Según Wikipedia, el Bloc de notas requiere que la BOM reconozca un archivo como UTF-8, y Google Docs también lo agrega al exportar un archivo como texto. Dudo que todos lo hagan por error .
ilkkachu
Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat .
terdon
1
¿Hay alguna forma de no convertir las terminaciones de línea y simplemente eliminar la lista de materiales dos2unix?
m13r
2
@ m13r Luego usa el script sed en esta respuesta . Eso eliminará solo el bom (si existe), nada más se cambiará.
Flecha
27

Es posible eliminar la lista de materiales de un archivo con el tailcomando:

tail -c +4 withBOM.txt > withoutBOM.txt
m13r
fuente
2
¿Por qué 4? La lista de materiales tiene 3 bytes.
deviantfan
10
@deviantfan Es por eso que debe comenzar en el 4to byte si desea omitirlo.
Stéphane Chazelas
99
tail¿Está usando 1 indexación basada? WTF!
CodesInChaos
55
@CodesInChaos, tail -c -1o tail -c 1(para lo tailque generalmente se usa) es el contenido que comienza con el último byte, tail -c +1comenzando con el primer byte. tail -c 0/ tail -c +0porque eso sería mucho menos intuitivo.
Stéphane Chazelas
2
@deviantfan: (dd bs=1 count=3 of=/dev/null; cat) <input >output. O con GNU (head -c3 >/dev/null; cat), incluso en UTF8 u otro entorno local que no sea de un solo byte; La cabeza de GNU hace 'char' = byte.
dave_thompson_085
20

Usando VIM

  1. Abrir archivo en VIM:

    vi text.xml
    
  2. Eliminar la codificación BOM:

    :set nobomb
    
  3. Guardar y Salir:

    :wq
    
Joshua Pinter
fuente
Curiosamente con vim 8 en una mac, tengo un archivo csv utf-8 creado por Excel y comienza con <feff>, pero :set nobombno lo modifica ni lo elimina.
dlamblin
5

Puedes usar

LANG=C LC_ALL=C sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- filename

para eliminar la marca de orden de bytes desde el comienzo del archivo, si tiene alguna, así como para convertir cualquier nueva línea CR LF a solo LF. El LANG=C LC_ALL=Cle dice al shell que desea que el comando se ejecute en la configuración regional C predeterminada (también conocida como la configuración regional POSIX predeterminada), donde los tres bytes que forman la marca de orden de bytes se tratan como bytes. La -iopción de sed significa en el lugar. Si lo usa -i.old, sed guarda el archivo original como filename.oldy el nuevo archivo (con las modificaciones, si corresponde) como filename.


Personalmente me gusta tener esto como ~/bin/fix-ms; por ejemplo, como

#!/bin/dash
export LANG=C LC_ALL=C
if [ $# -gt 0 ]; then
    for FILE in "$@" ; do
        sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- "$FILE" || exit 1
    done
else
    exec sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//'
fi

así que si necesito aplicar esto para decir todos los archivos y encabezados de fuente C (¡mi código anterior de la era MS-DOS, por ejemplo!), simplemente ejecuto

find . -name '*.[CHch]' -print0 | xargs -r0 ~/bin/ms-fix

o, si solo quiero ver dicho archivo, sin modificarlo, puedo ejecutar

~/bin/ms-fix < filename | less

y no ver lo feo <U+FEFF>en mi terminal UTF-8.

Animal nominal
fuente
¿Por qué no simplemente sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- "$@"?
Stéphane Chazelas
@ StéphaneChazelas: Porque quiero que el script salga de inmediato si hay un problema con un reemplazo, que sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- "$@"no funciona; devuelve un código de salida, pero procesa todos los archivos enumerados en la lista de argumentos antes de salir.
Nominal Animal
@ StéphaneChazelas: Por --supuesto, antes de los nombres de archivo es importante: sin él, sed puede considerar opciones de archivo que comienzan con un guión. Los edité en mi respuesta; ¡Gracias por el recordatorio!
Nominal Animal
0

Recientemente encontré esta pequeña herramienta de línea de comandos que agrega o elimina la lista de materiales en archivos codificados UTF-8 arbitrarios: UTF BOM Utils ( nuevo enlace en github)

Pequeño inconveniente, solo puede descargar el código fuente de C ++. Debe crear el archivo MAKE (con CMake , por ejemplo) y compilarlo usted mismo, no se proporcionan binarios en esta página.

Wernfried Domscheit
fuente