shell - txt - Conversión por lotes de archivos latin-1 a utf-8 usando iconv
convertir subtitulos srt a utf-8 (11)
Algunas buenas respuestas, pero encontré esto mucho más fácil en mi caso con un directorio anidado de cientos de archivos para convertir:
ADVERTENCIA: Esto escribirá los archivos en su lugar, así que haga una copia de seguridad
$ vim $(find . -type f)
# in vim, go into command mode (:)
:set nomore
:bufdo set fileencoding=utf8 | w
Tengo este proyecto PHP en mi OSX que está en codificación latin1. Ahora necesito convertir archivos a UTF8. No soy mucho un programador de shell y probé algo que encontré en internet:
mkdir new
for a in `ls -R *`; do iconv -f iso-8859-1 -t utf-8 <"$a" >new/"$a" ; done
Pero eso no crea la estructura de directorios y me da una gran cantidad de errores cuando se ejecuta. ¿Alguien puede llegar a una solución ordenada?
Creo el siguiente script que (i) hace una copia de seguridad de todos los archivos de tex en el directorio "convertido", (ii) verifica la codificación de cada archivo de tex y (iii) convierte a UTF-8 solo los archivos de tex en la norma ISO-8859-1 codificación
FILES=*.tex
for f in $FILES
do
filename="${f%.*}"
echo -n "$f"
#file -I $f
if file -I $f | grep -wq "iso-8859-1"
then
mkdir -p converted
cp $f ./converted
iconv -f ISO-8859-1 -t UTF-8 $f > "${filename}_utf8.tex"
mv "${filename}_utf8.tex" $f
echo ": CONVERTED TO UTF-8."
else
echo ": UTF-8 ALREADY."
fi
done
En unix.stackexchange.com se hizo una pregunta similar, y el administrador de usuarios sugirió recode, que funciona muy bien.
Lo he estado usando para convertir ucs-2 a utf-8 en su lugar
recode ucs-2..utf-8 *.txt
Esto convierte todos los archivos con la extensión de nombre de archivo .php
- en el directorio actual y sus subdirectorios - preservando la estructura del directorio:
find . -name "*.php" -exec sh -c "iconv -f ISO-8859-1 -t UTF-8 {} > {}.utf8" /; -exec mv "{}".utf8 "{}" /;
Notas:
Para obtener una lista de los archivos que se seleccionarán de antemano, simplemente ejecute el comando sin los indicadores -exec
(como este: find . -name "*.php"
). Hacer una copia de seguridad es una buena idea.
El uso de sh
como esto permite canalizar y redireccionar con -exec, lo cual es necesario porque no todas las versiones de iconv son compatibles con el distintivo -o
.
Agregar .utf8
al nombre de archivo de la salida y luego eliminarlo puede parecer extraño pero es necesario. El uso del mismo nombre para los archivos de entrada y salida puede causar los siguientes problemas:
Para archivos grandes (alrededor de 30 KB en mi experiencia) causa un volcado del núcleo (o
termination by signal 7
)Algunas versiones de iconv parecen crear el archivo de salida antes de leer el archivo de entrada, lo que significa que si los archivos de entrada y salida tienen el mismo nombre, el archivo de entrada se sobrescribe con un archivo vacío antes de leerlo.
No deberías usar ls
así y un bucle for
tampoco es apropiado. Además, el directorio de destino debe estar fuera del directorio de origen.
mkdir /path/to/destination
find . -type f -exec iconv -f iso-8859-1 -t utf-8 "{}" -o /path/to/destination/"{}" /;
No hay necesidad de un bucle. La opción -type f
incluye archivos y excluye directorios.
Editar:
La versión OS X de iconv
no tiene la opción -o
. Prueba esto:
find . -type f -exec bash -c ''iconv -f iso-8859-1 -t utf-8 "{}" > /path/to/destination/"{}"'' /;
Para convertir un árbol de directorios completo recursivamente de iso-8859-1 a utf-8, incluida la creación de subdirectorios, ninguna de las soluciones cortas anteriores funcionó para mí porque la estructura de directorios no se creó en el destino. Basado en la respuesta de Dennis Williamsons, se me ocurrió la siguiente solución:
find . -type f -exec bash -c ''t="/tmp/dest"; mkdir -p "$t/`dirname {}`"; iconv -f iso-8859-1 -t utf-8 "{}" > "$t/{}"'' /;
Creará un clon del subárbol del directorio actual en /tmp/dest
(ajuste a sus necesidades) incluyendo todos los subdirectorios y con todos iso-8859-1
archivos iso-8859-1
convertidos a utf-8
. Probado en macosx.
Por cierto: compruebe sus codificaciones de archivos con:
file -I file.php
para obtener la información de codificación.
Espero que esto ayude.
Si todos los archivos que tiene que convertir son .php, podría usar lo siguiente, que es recursivo por defecto:
for a in $(find . -name "*.php"); do iconv -f iso-8859-1 -t utf-8 <"$a" >new/"$a" ; done
Creo que sus errores se debieron al hecho de que ls -R
también produce una salida que podría no ser reconocida por iconv como un nombre de archivo válido, algo así como ./my/dir/structure:
Todo está bien con las respuestas anteriores, pero si este es un proyecto "mixto", es decir, ya hay archivos UTF8, entonces podemos meternos en problemas, por lo tanto, esta es mi solución. Primero estoy revisando la codificación del archivo.
#!/bin/bash
# file name: to_utf8
# current encoding:
encoding=$(file -i "$1" | sed "s/.*charset=/(.*/)$//1/")
if [ "${encoding}" = "iso-8859-1" ] || [ "${encoding}" = "iso-8859-2" ];
then
echo "recoding from ${encoding} to UTF-8 file : $1"
recode ISO-8859-2..UTF-8 "$1"
fi
#example:
#find . -name "*.php" -exec to_utf8 {} /;
Usando las respuestas de Dennis Williamson y Alberto Zaccagni, se me ocurrió la siguiente secuencia de comandos que convierte todos los archivos del tipo de archivo especificado de todos los subdirectorios. Luego, la salida se recopila en una carpeta proporcionada por /path/to/destination
mkdir /path/to/destination
for a in $(find . -name "*.php");
do
filename=$(basename $a);
echo $filename
iconv -f iso-8859-1 -t utf-8 <"$a" >"/path/to/destination/$filename";
done
La función nombre base devuelve el nombre de archivo sin la ruta del archivo.
Alternativa (interactiva para el usuario): ahora también creé una secuencia de comandos interactiva para el usuario que le permite decidir si desea sobrescribir los archivos antiguos o simplemente cambiarles el nombre. Gracias adicionales van a tbsalling
for a in $(find . -name "*.tex");
do
iconv -f iso-8859-1 -t utf-8 <"$a" >"$a".utf8 ;
done
echo "Should the original files be replaced (Y/N)?"
read replace
if [ "$replace" == "Y" ]; then
echo "Original files have been replaced."
for a in $(find . -name "*.tex.utf8");
do
file_no_suffix=$(basename -s .tex.utf8 "$a");
directory=$(dirname "$a");
mv "$a" "$directory"/"$file_no_suffix".tex;
done
else
echo "Original files have been converted and converted files were saved with suffix ''.utf8''"
fi
Diviértete con esto y agradecería cualquier comentario para mejorarlo, ¡gracias!
Utilice mkdir -p "${a%/*}";
antes de iconv.
Tenga en cuenta que está utilizando una construcción potencialmente peligrosa cuando hay espacios en los nombres de archivo, consulte http://porkmail.org/era/unix/award.html .
find . -iname "*.php" | xargs -I {} echo "iconv -f ISO-8859-1 -t UTF-8 /"{}/" > /"{}-utf8.php/""