Comment trouver l'encodage d'un fichier via un script sous Linux?

303

J'ai besoin de trouver l'encodage de tous les fichiers qui sont placés dans un répertoire. Existe-t-il un moyen de trouver l'encodage utilisé?

La filecommande n'est pas en mesure de le faire.

L'encodage qui m'intéresse est: ISO-8859-1. Si l'encodage est autre chose, je veux déplacer le fichier vers un autre répertoire.

Manglu
la source
1
Si vous avez une idée du type de langage de script que vous souhaitez utiliser, marquez votre question avec le nom de ce langage. Cela pourrait aider ...
MatrixFrog
1
Ou peut-être qu'il essaie juste de construire un script shell?
Shalom Craimer
1
Ce serait une réponse à «quel langage de script».
bignose le
7
Peut-être pas lié à cette réponse, mais un conseil en général: quand vous pouvez décrire votre doute entier en un mot ("encodage", ici), faites-le apropos encoding. Il recherche les titres et les descriptions de toutes les pages de manuel. Quand je fais cela sur ma machine, je vois 3 outils qui pourraient me aider, à en juger par leurs descriptions: chardet, chardet3, chardetect3. Ensuite, en faisant man chardetet en lisant la page de manuel me dit que chardetc'est juste l'utilitaire dont j'ai besoin.
John Red
1
L'encodage peut changer lorsque vous modifiez le contenu d'un fichier. Par exemple, dans vi, lors de l'écriture d'un programme c simple, c'est probablement us-ascii, mais après avoir ajouté une ligne de commentaire chinois, cela devient utf-8. filepeut dire l'encodage en lisant le contenu du fichier et devinez.
Eric Wang

Réponses:

419

Cela ressemble à ce que vous recherchez enca. Il peut deviner et même convertir entre les encodages. Regardez la page de manuel .

Ou, à défaut, utilisez file -i(linux) ou file -I(osx). Cela produira des informations de type MIME pour le fichier, qui comprendra également l'encodage du jeu de caractères. J'ai aussi trouvé une page de manuel pour ça :)

Shalom Craimer
la source
1
Selon la page de manuel, il connaît l'ensemble ISO 8559. Peut-être lu un peu moins de manière cursive :-)
bignose
5
Enca semble intéressant. Malheureusement, la détection semble être très dépendante de la langue et l'ensemble des langues prises en charge n'est pas très important. Le mien (de) est manquant :-( Quoi qu'il en soit, un outil cool.
er4z0r
1
Bon article sur des outils comme enca, enconv, convmv
GuruM
6
encasemble être complètement inutile pour analyser un fichier écrit en anglais, mais si vous regardez quelque chose en estonien, cela pourrait résoudre tous vos problèmes. Outil très utile, qui ... </
sarcasm
6
@vladkras s'il n'y a pas de caractères non-ascii dans votre fichier utf-8, alors il est impossible de les distinguer de ascii :)
vadipp
85
file -bi <file name>

Si vous aimez le faire pour un tas de fichiers

for f in `find | egrep -v Eliminate`; do echo "$f" ' -- ' `file -bi "$f"` ; done
madu
la source
Cependant, si le fichier est un fichier xml, avec l'attribut "encoding = 'iso-8859-1' dans la déclaration xml, la commande file dira qu'il s'agit d'un fichier iso, même si le véritable encodage est utf-8 ...
par le
6
Pourquoi utilisez-vous l'argument -b? Si vous faites juste le fichier -i *, il sort le jeu de caractères deviné pour chaque fichier.
Hans-Peter Störr
4
J'étais également curieux de connaître l'argument -b. La page de manuel indique que cela signifie "bref"Do not prepend filenames to output lines
craq
1
Il n'est pas nécessaire d'analyser la sortie du fichier, génère file -b --mime-encodinguniquement l'encodage du jeu de caractères
jesjimher
-b signifie «être bref», ce qui signifie essentiellement ne pas afficher le nom de fichier que vous venez de donner.
Nikos
36

uchardet - Une bibliothèque de détecteurs d'encodage portée depuis Mozilla.

Usage:

~> uchardet file.java 
UTF-8

Diverses distributions Linux (Debian / Ubuntu, OpenSuse-packman, ...) fournissent des binaires.

qwert2003
la source
1
Merci! Je ne suis pas ravi d'avoir encore plus de paquets, mais sudo apt-get install uchardetc'est si facile que j'ai décidé de ne pas m'en inquiéter ...
sage
Comme je viens de le dire dans un commentaire ci-dessus: uchardet me dit à tort que l'encodage d'un fichier était "windows-1252", bien que j'aie explicitement enregistré ce fichier en UTF-8. uchardet ne dit même pas "avec confiance 0,4641618497109827", ce qui vous donnerait au moins un indice que cela vous dit un non-sens complet. file, enca et encguess ont fonctionné correctement.
Algoman
uchardeta un gros avantage sur fileet enca, en ce qu'il analyse le fichier entier (juste essayé avec un fichier 20GiB) par opposition au seul début.
tuxayo
10

voici un exemple de script utilisant le fichier -I et iconv qui fonctionne sur MacOsX Pour votre question, vous devez utiliser mv au lieu 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
Wolfgang Fahl
la source
6
file -b --mime-encodingne produit que le jeu de caractères, vous pouvez donc éviter tout traitement de tuyau
jesjimher
1
THX. Comme indiqué sur MacOS, cela ne fonctionnera pas: fichier -b --mime-encoding Utilisation: fichier [-bchikLNnprsvz0] [-e test] [-f nomfichier] [-F séparateur] [-m magicfiles] [-M magicfiles ] file ... file -C -m magicfiles Essayez `file --help 'pour plus d'informations.
Wolfgang Fahl
6

Il est vraiment difficile de déterminer s'il s'agit de l'iso-8859-1. Si vous avez un texte avec seulement 7 caractères binaires qui pourrait également être iso-8859-1 mais vous ne savez pas. Si vous avez des caractères à 8 bits, les caractères de la région supérieure existent également dans l'ordre des codages. Pour cela, vous devrez utiliser un dictionnaire pour mieux deviner de quel mot il s'agit et déterminer à partir de là quelle lettre il doit être. Enfin, si vous détectez que ce pourrait être utf-8, vous êtes sûr que ce n'est pas iso-8859-1

L'encodage est l'une des choses les plus difficiles à faire car vous ne savez jamais si rien ne vous dit

Norbert Hartl
la source
Il peut être utile d'essayer de recourir à la force brute. La commande suivante essaiera de convertir de tous les formats de codage électronique avec des noms commençant par WIN ou ISO en UTF8. Ensuite, il faudrait vérifier manuellement la sortie à la recherche d'un indice dans le bon codage. Bien sûr, vous pouvez modifier les formats filtrés en remplaçant ISO ou WIN pour quelque chose de approprié ou supprimer le filtre en supprimant la commande grep. pour i dans $ (iconv -l | tail -n +2 | grep "(^ ISO \ | ^ WIN)" | sed -e 's / \ / \ ///'); faire écho $ i; iconv -f $ i -t UTF8 santos; terminé;
ndvo
5

Dans Debian, vous pouvez également utiliser encguess:

$ encguess test.txt
test.txt  US-ASCII
not2qubit
la source
J'ai installé uchardetdans Ubuntu et il m'a dit que mon fichier l'était WINDOWS-1252. Je sais que c'était faux parce que je l'ai enregistré en UTF-16 avec Kate, pour le tester. Cependant, encguessdevinez correctement, et il a été préinstallé dans Ubuntu 19.04.
Nagev
5

Pour convertir le codage de 8859 en ASCII:

iconv -f ISO_8859-1 -t ASCII filename.txt
fimbulwinter
la source
4

Avec Python, vous pouvez utiliser le module chardet: https://github.com/chardet/chardet

fccoelho
la source
Domaine inexistant: feedparser.org
Rune
À partir de ce commentaire, il est toujours disponible sur Github: github.com/dcramer/chardet
Rick Hanlon II
À partir de ce commentaire, c'est sur chardet / chardet sur github. Réponse mise à jour.
Quentin Pradet
rapports de chardet « Aucun », bobines d' arrêt de chardet3 sur la première ligne du fichier dans l' exacte même façon que mon script python fait.
Joels Elf
3

Ce n'est pas quelque chose que vous pouvez faire à toute épreuve. Une possibilité serait d'examiner chaque caractère du fichier pour s'assurer qu'il ne contient aucun caractère dans les plages 0x00 - 0x1fou 0x7f -0x9fmais, comme je l'ai dit, cela peut être vrai pour n'importe quel nombre de fichiers, y compris au moins une autre variante d'ISO8859.

Une autre possibilité consiste à rechercher des mots spécifiques dans le fichier dans toutes les langues prises en charge et à voir si vous pouvez les trouver.

Ainsi, par exemple, recherchez l'équivalent de l'anglais "et", "mais", "à", "de" et ainsi de suite dans toutes les langues prises en charge de 8859-1 et voyez si elles ont un grand nombre d'occurrences dans le fichier.

Je ne parle pas de traduction littérale comme:

English   French
-------   ------
of        de, du
and       et
the       le, la, les

bien que ce soit possible. Je parle de mots communs dans la langue cible (pour autant que je sache, l'islandais n'a pas de mot pour "et" - vous devrez probablement utiliser leur mot pour "poisson" [désolé, c'est un peu stéréotypé, je ne l'ai pas signifie toute infraction, illustrant simplement un point]).

paxdiablo
la source
2

Je sais que vous êtes intéressé par une réponse plus générale, mais ce qui est bon en ASCII est généralement bon dans d'autres encodages. Voici une ligne unique en Python pour déterminer si l'entrée standard est ASCII. (Je suis sûr que cela fonctionne en Python 2, mais je ne l'ai testé que sur 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
wkschwartz
la source
2

Si vous parlez de fichiers XML (ISO-8859-1), la déclaration XML à l'intérieur d'eux spécifie l'encodage: <?xml version="1.0" encoding="ISO-8859-1" ?>
Ainsi, vous pouvez utiliser des expressions régulières (par exemple avec perl) pour vérifier chaque fichier pour une telle spécification.
Vous trouverez plus d'informations ici: Comment déterminer le codage d'un fichier texte .

evgeny9
la source
eh bien cette ligne pourrait être copiée-collée par quelqu'un qui ne sait pas quel encodage il utilise.
Algoman
Attention, rien dans la déclaration en haut ne garantit que le fichier est réellement encodé de cette façon. Si vous vous souciez vraiment de l'encodage dont vous avez besoin pour le valider vous-même.
Jazzepi
2

En php, vous pouvez vérifier comme ci-dessous:

Spécification explicite de la liste d'encodage:

php -r "echo 'probably : ' . mb_detect_encoding(file_get_contents('myfile.txt'), 'UTF-8, ASCII, JIS, EUC-JP, SJIS, iso-8859-1') . PHP_EOL;"

"Mb_list_encodings" plus précis:

php -r "echo 'probably : ' . mb_detect_encoding(file_get_contents('myfile.txt'), mb_list_encodings()) . PHP_EOL;"

Ici, dans le premier exemple, vous pouvez voir que j'ai mis une liste d'encodages (détecter l'ordre des listes) qui pourraient correspondre. Pour avoir un résultat plus précis, vous pouvez utiliser tous les encodages possibles via: mb_list_encodings ()

Remarque: les fonctions mb_ * nécessitent php-mbstring

apt-get install php-mbstring
Mohamed23gharbi
la source
0

Chez Cygwin, cela semble fonctionner pour moi:

find -type f -name "<FILENAME_GLOB>" | while read <VAR>; do (file -i "$<VAR>"); done

Exemple:

find -type f -name "*.txt" | while read file; do (file -i "$file"); done

Vous pouvez diriger cela vers awk et créer une commande iconv pour tout convertir en utf8, à partir de n'importe quel encodage source pris en charge par iconv.

Exemple:

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
skeetastax
la source
0

Vous pouvez extraire l'encodage d'un seul fichier avec la commande file. J'ai un fichier sample.html avec:

$ file sample.html 

sample.html: document HTML, texte Unicode UTF-8, avec de très longues lignes

$ file -b sample.html

Document HTML, texte Unicode UTF-8, avec de très longues lignes

$ file -bi sample.html

text / html; charset = utf-8

$ file -bi sample.html  | awk -F'=' '{print $2 }'

utf-8

Daniel Faure
la source
1
la sortie que j'obtiens est juste un "fichier normal"
Mordechai
0

J'utilise le script suivant pour

  1. Trouver tous les fichiers qui correspondent à FILTER avec SRC_ENCODING
  2. Créez-en une sauvegarde
  3. Convertissez-les en DST_ENCODING
  4. (facultatif) Supprimez les sauvegardes

.

#!/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 {} \;
Matyas
la source
0

avec cette commande:

for f in `find .`; do echo `file -i "$f"`; done

vous pouvez lister tous les fichiers dans un répertoire et des sous-répertoires et l'encodage correspondant.

danilo
la source
-2

Avec Perl, utilisez Encode :: Detect.

manu_v
la source
7
Pouvez-vous donner un exemple sur la façon de l'utiliser dans le shell?
Lri
Une autre affiche (@fccoelho) a fourni un module Python comme solution qui obtient un +3 et cette affiche obtient un -2 pour une réponse très très similaire, sauf qu'il s'agit d'un module Perl. Pourquoi le double standard?!
Happy Green Kid Naps
4
Peut-être qu'un exemple de code d'un Perl one-liner aiderait cette réponse.
vikingsteve