2009-06-25 20 views
10

Tengo un archivo SQL bastante grande que comienza con el marcador de orden de bytes de FFFE. He dividido este archivo usando la herramienta de división de Linux consciente de unicode en 100.000 fragmentos de línea. Pero al pasar estos a Windows, hace no como cualquiera de las partes que no sean la primera ya que solo tiene el marcador de orden de bytes FFFE activado.¿Cómo puedo volver a agregar un marcador de orden de bytes unicode en Linux?

¿Cómo puedo agregar este código de dos bytes usando echo (o cualquier otro comando bash)?

Respuesta

4

Algo así como (primera copia de seguridad)): Respuesta

for i in $(ls *.sql) 
do 
    cp "$i" "$i.temp" 
    printf '\xFF\xFE' > "$i" 
    cat "$i.temp" >> "$i" 
    rm "$i.temp" 
done 
+0

printf! Gracias amigo, creo que habría estado buscando en Google hasta el final de los tiempos. –

+6

El punto de código BOM es U + FEFF pero su representación literal en UTF-8 es 'EF BB BF' (tres bytes). Esto solo funcionaría si el archivo ya estaba en UTF-16, orden little endian. Ver http://en.wikipedia.org/wiki/Byte_order_mark#Representations_of_byte_order_marks_by_encoding – pimlottc

2

de Matthew Flaschen es una buena idea, sin embargo, tiene un par de defectos.

  • No hay comprobación de que la copia tuvo éxito antes de que se trunque el archivo original. Sería mejor hacer que todo dependa de una copia exitosa, o probar la existencia del archivo temporal, o para operar en la copia. Si eres un tipo de persona con cinturón y tirantes, harías un combo como lo he ilustrado a continuación
  • El ls es innecesario.
  • Usaría un nombre de variable mejor que "i", quizás "archivo".

Por supuesto, usted podría ser muy paranoico y comprobar la existencia del archivo temporal al principio para que no accidentalmente sobreescribe y/o el uso de un UUID o un nombre de archivo generado. Uno de mktemp, tempfile o uuidgen haría el truco.

td=TMPDIR 
export TMPDIR= 

usertemp=~/temp   # set this to use a temp directory on the same filesystem 
          # you could use ./temp to ensure that it's one the same one 
          # you can use mktemp -d to create the dir instead of mkdir 

if [[ ! -d $usertemp ]] # if this user temp directory doesn't exist 
then      # then create it, unless you can't 
    mkdir $usertemp || export TMPDIR=$td # if you can't create it and TMPDIR is/was 
fi           # empty then mktemp automatically falls 
              # back to /tmp 

for file in *.sql 
do 
    # TMPDIR if set overrides the argument to -p 
    temp=$(mktemp -p $usertemp) || { echo "$0: Unable to create temp file."; exit 1; } 

    { printf '\xFF\xFE' > "$temp" && 
    cat "$file" >> "$temp"; } || { echo "$0: Write failed on $file"; exit 1; } 

    { rm "$file" && 
    mv "$temp" "$file"; } || { echo "$0: Replacement failed for $file; exit 1; } 
done 
export TMPDIR=$td 

Las trampas pueden ser mejores que todos los manejadores de errores que he agregado.

Sin duda, toda esta precaución adicional es excesiva para un script de un solo intento, pero estas técnicas pueden ahorrarle cuando se trata de empujar, especialmente en una operación de varios archivos.

+1

El comando "cp" no es necesario. También "mktemp" devuelve un nombre en/tmp; sería mejor escribir el archivo temporal en el mismo sistema de archivos para que "mv" no tenga que copiarlo. – mark4o

+0

@ mark4o: Tiene razón en ambos aspectos. He actualizado mi respuesta en consecuencia. –

9

Para una solución, algo de propósito general que establece la marca de orden de bytes correcta independientemente de si el archivo es UTF-8, UTF-16 o UTF-32-Me gustaría utilizar la opción de vim 'bomb':

$ echo 'hello' > foo 
$ xxd < foo 
0000000: 6865 6c6c 6f0a       hello. 
$ vim -e -s -c ':set bomb' -c ':wq' foo 
$ xxd < foo 
0000000: efbb bf68 656c 6c6f 0a     ...hello. 

(-e significa que se ejecuta en modo ex lugar de modo visual; -s medios no se imprimen los mensajes de estado; -c significa “hacer esto”)

10

para añadir a las listas de materiales de todos los archivos que comienzan con "foo" , puede usar sed. sed tiene una opción para hacer una copia de seguridad.

sed -i '1s/^\(\xff\xfe\)\?/\xff\xfe/' foo-* 

strace ing Esto demuestra sed crea un archivo temporal con un nombre que empieza con "sed". Si usted sabe con certeza que no hay lista de materiales ya, puede simplificar el comando:

sed -i '1s/^/\xff\xfe/' foo-* 

Asegúrese de que es necesario establecer UTF-16, es decir, debido a UTF-8 es diferente.

+1

Para UTF-8 use '\ xef \ xbb \ xbf'; para UTF-16 little-endian use '\ xff \ xfe'; para UTF-16 big-endian use '\ xfe \ xff'. Ver https://www.w3.org/International/questions/qa-byte-order-mark –

+0

Subiendo esta respuesta porque esto es lo que uso yo mismo. Mac OS y otros usuarios de BSD deben tener en cuenta que la opción '-i, - inplace' no está especificada por POSIX y solo está disponible con GNU sed. –

+1

Por cierto, el modificador 'g' (global) no hace nada aquí. –

3

Trate uconv

uconv --add-signature 
+1

uconv necesita ser instalado (en Debian, está en el paquete libicu-dev). No es que add-signature no funcione si el archivo está en otra codificación. – Rob

13

Basado en sed de solution of Anonymous, sed -i '1s/^/\xef\xbb\xbf/' foo añade a la lista de materiales del archivo codificado en UTF-8 foo. Muy útil es que también convierte archivos ASCII a UTF8 BOM con

0
$ printf '\xEF\xBB\xBF' > bom.txt 

A continuación, compruebe:

$ grep -rl $'\xEF\xBB\xBF' . 
./bom.txt 
Cuestiones relacionadas