¿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


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

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

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

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
    

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.


¿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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.