Cómo encontrar la codificación de un archivo en Unix a través de scripts
Pregunta
Necesito encontrar la codificación de todos los archivos que se colocan en un directorio. ¿Hay alguna forma de encontrar la codificación utilizada?
El comando file
no puede hacer esto.
La codificación que me interesa es: ISO-8859-1. Si la codificación es otra cosa, quiero mover el archivo a otro directorio.
Solución
Parece que estás buscando enca
. Puede adivinar e incluso convertir entre codificaciones. Solo mire la página del manual .
O, en su defecto, use file -i
(linux) o file -I
(osx). Eso generará información de tipo MIME para el archivo, que también incluirá la codificación del juego de caracteres. Encontré una página de manual para ello también :)
Otros consejos
file -bi <file name>
Si desea hacer esto para un montón de archivos
for f in `find | egrep -v Eliminate`; do echo "$f" ' -- ' `file -bi "$f"` ; done
uchardet : una biblioteca de detectores de codificación portada desde Mozilla.
Uso:
~> uchardet file.java
UTF-8
Varias distribuciones de Linux (Debian / Ubuntu, OpenSuse-packman, ...) proporcionan binarios.
aquí hay un script de ejemplo que usa el archivo -I e iconv que funciona en MacOsX Para su pregunta, debe usar mv en lugar de iconv
#!/bin/bash
# 2016-02-08
# check encoding and convert files
for f in *.java
do
encoding=`file -I $f | cut -f 2 -d";" | cut -f 2 -d=`
case $encoding in
iso-8859-1)
iconv -f iso8859-1 -t utf-8 $f > $f.utf8
mv $f.utf8 $f
;;
esac
done
Es realmente difícil determinar si es iso-8859-1. Si tiene un texto con solo caracteres de 7 bits que también podría ser iso-8859-1 pero no lo sabe. Si tiene caracteres de 8 bits, los caracteres de la región superior también existen en codificaciones de orden. Por lo tanto, tendría que usar un diccionario para adivinar mejor qué palabra es y determinar a partir de ahí qué letra debe ser. Finalmente, si detecta que puede ser utf-8, entonces está seguro de que no es iso-8859-1
La codificación es una de las cosas más difíciles de hacer porque nunca se sabe si nada te dice
Con Python, puede usar el módulo chardet: https://github.com/chardet/chardet
En Debian también puede usar: encguess
:
$ encguess test.txt
test.txt US-ASCII
Esto no es algo que puedas hacer de una manera infalible. Una posibilidad sería examinar cada carácter en el archivo para asegurarse de que no contenga ningún carácter en los rangos 0x00 - 0x1f
o 0x7f -0x9f
pero, como dije, esto puede ser cierto para cualquier número de archivos, incluido al menos otra variante de ISO8859.
Otra posibilidad es buscar palabras específicas en el archivo en todos los idiomas admitidos y ver si puede encontrarlas.
Entonces, por ejemplo, encuentre el equivalente del inglés " y " ;, " pero " ;, " a " ;, " de " y así sucesivamente en todos los idiomas admitidos de 8859-1 y ver si tienen una gran cantidad de ocurrencias dentro del archivo.
No estoy hablando de traducción literal como:
English French
------- ------
of de, du
and et
the le, la, les
aunque eso es posible. Estoy hablando de palabras comunes en el idioma de destino (por lo que sé, islandés no tiene palabra para & Quot; y & Quot; - probablemente tendría que usar su palabra para & Quot; fish " [lo siento, es un poco estereotipado, no quise decir ninguna ofensa, solo ilustrando un punto]).
Si está hablando de archivos XML (ISO-8859-1), la declaración XML dentro de ellos especifica la codificación: <?xml version="1.0" encoding="ISO-8859-1" ?>
Por lo tanto, puede usar expresiones regulares (por ejemplo, con perl
) para verificar cada archivo para dicha especificación.
Puede encontrar más información aquí: Cómo determinar la codificación de archivos de texto .
Para convertir la codificación de 8859 a ASCII:
iconv -f ISO_8859-1 -t ASCII filename.txt
Sé que está interesado en una respuesta más general, pero lo que es bueno en ASCII generalmente es bueno en otras codificaciones. Aquí hay una línea única de Python para determinar si la entrada estándar es ASCII. (Estoy bastante seguro de que esto funciona en Python 2, pero solo lo he probado en Python 3.)
python -c 'from sys import exit,stdin;exit()if 128>max(c for l in open(stdin.fileno(),"b") for c in l) else exit("Not ASCII")' < myfile.txt
En Cygwin, parece que funciona para mí:
find -type f -name "<FILENAME_GLOB>" | while read <VAR>; do (file -i "$<VAR>"); done
Ejemplo:
find -type f -name "*.txt" | while read file; do (file -i "$file"); done
Puede canalizar eso a awk y crear un comando iconv para convertir todo a utf8, desde cualquier codificación de fuente compatible con iconv.
Ejemplo:
find -type f -name "*.txt" | while read file; do (file -i "$file"); done | awk -F[:=] '{print "iconv -f "$3" -t utf8 \""$1"\" > \""$1"_utf8\""}' | bash
Puede extraer la codificación de un solo archivo con el comando de archivo. Tengo un archivo sample.html con:
$ file sample.html
sample.html: documento HTML, texto UTF-8 Unicode, con líneas muy largas
$ file -b sample.html
Documento HTML, texto Unicode UTF-8, con líneas muy largas
$ file -bi sample.html
texto / html; charset = utf-8
$ file -bi sample.html | awk -F'=' '{print $2 }'
utf-8
Estoy usando el siguiente script para
- Encuentra todos los archivos que coinciden con FILTER con SRC_ENCODING
- Crear una copia de seguridad de ellos
- Conviértalos a DST_ENCODING
- (opcional) Eliminar las copias de seguridad
.
#!/bin/bash -xe
SRC_ENCODING="iso-8859-1"
DST_ENCODING="utf-8"
FILTER="*.java"
echo "Find all files that match the encoding $SRC_ENCODING and filter $FILTER"
FOUND_FILES=$(find . -iname "$FILTER" -exec file -i {} \; | grep "$SRC_ENCODING" | grep -Eo '^.*\.java')
for FILE in $FOUND_FILES ; do
ORIGINAL_FILE="$FILE.$SRC_ENCODING.bkp"
echo "Backup original file to $ORIGINAL_FILE"
mv "$FILE" "$ORIGINAL_FILE"
echo "converting $FILE from $SRC_ENCODING to $DST_ENCODING"
iconv -f "$SRC_ENCODING" -t "$DST_ENCODING" "$ORIGINAL_FILE" -o "$FILE"
done
echo "Deleting backups"
find . -iname "*.$SRC_ENCODING.bkp" -exec rm {} \;
Con Perl, use Encode :: Detect.