Wie finde ich die Codierung einer Datei per Skript unter Linux?

303

Ich muss die Codierung aller Dateien finden, die in einem Verzeichnis abgelegt sind. Gibt es eine Möglichkeit, die verwendete Codierung zu finden?

Der fileBefehl kann dies nicht.

Die für mich interessante Codierung lautet: ISO-8859-1. Wenn die Codierung etwas anderes ist, möchte ich die Datei in ein anderes Verzeichnis verschieben.

Manglu
quelle
1
Wenn Sie eine Vorstellung davon haben, welche Art von Skriptsprache Sie möglicherweise verwenden möchten, kennzeichnen Sie Ihre Frage mit dem Namen dieser Sprache. Das könnte helfen ...
MatrixFrog
1
Oder versucht er nur, ein Shell-Skript zu erstellen?
Shalom Craimer
1
Welches wäre eine Antwort auf "welche Skriptsprache".
Bignose
7
Vielleicht nicht im Zusammenhang mit dieser Antwort, aber ein Tipp im Allgemeinen: Wenn Sie Ihren gesamten Zweifel in einem Wort beschreiben können ("Kodierung" hier), tun Sie es einfach apropos encoding. Es durchsucht die Titel und Beschreibungen aller Manpages. Wenn ich dies tun auf meiner Maschine, ich sehe drei Tools , die mir helfen könnten, durch ihre Beschreibungen zu urteilen: chardet, chardet3, chardetect3. man chardetWenn ich dann die Manpage mache und lese, weiß ich, dass dies chardetgenau das Dienstprogramm ist, das ich brauche.
John Red
1
Die Codierung kann sich ändern, wenn Sie den Inhalt einer Datei ändern. Beispiel: In vi ist es wahrscheinlich, wenn Sie ein einfaches c-Programm schreiben us-ascii, aber nach dem Hinzufügen einer Zeile mit chinesischen Kommentaren wird es utf-8. filekann die Codierung durch Lesen des Dateiinhalts und der Vermutung erkennen.
Eric Wang

Antworten:

419

Klingt wie Sie suchen enca. Es kann zwischen Codierungen raten und sogar konvertieren. Schauen Sie sich einfach die Manpage an .

Andernfalls verwenden Sie file -i(Linux) oder file -I(Osx). Dadurch werden Informationen vom Typ MIME für die Datei ausgegeben, die auch die Zeichensatzcodierung enthalten. Ich habe auch eine Manpage dafür gefunden :)

Shalom Craimer
quelle
1
Laut Manpage kennt es das ISO 8559-Set. Vielleicht etwas weniger
flüchtig
5
Enca klingt interessant. Leider scheint die Erkennung sehr sprachabhängig zu sein und die Anzahl der unterstützten Sprachen ist nicht sehr groß. Mine (de) fehlt :-( Wie auch immer cooles Tool.
er4z0r
1
Guter Beitrag zu Tools wie enca, enconv, convmv
GuruM
6
encaEs scheint völlig nutzlos zu sein, eine auf Englisch geschriebene Datei zu analysieren. Wenn Sie sich jedoch etwas auf Estnisch ansehen, kann dies möglicherweise alle Ihre Probleme lösen. Sehr hilfreiches Tool, das ... </
sarcasm
6
@vladkras Wenn Ihre utf-8-Datei keine Nicht-ASCII-Zeichen enthält, ist sie nicht von
ASCII
85
file -bi <file name>

Wenn Sie dies für eine Reihe von Dateien tun möchten

for f in `find | egrep -v Eliminate`; do echo "$f" ' -- ' `file -bi "$f"` ; done
Madu
quelle
Wenn es sich bei der Datei jedoch um eine XML-Datei mit dem Attribut "encoding = 'iso-8859-1' in der XML-Deklaration handelt, gibt der Befehl file an, dass es sich um eine ISO-Datei handelt, auch wenn die wahre Codierung utf-8 ist ...
Per
6
Warum verwenden Sie das Argument -b? Wenn Sie nur die Datei -i * ausführen, wird für jede Datei der erratene Zeichensatz ausgegeben.
Hans-Peter Störr
4
Ich war auch neugierig auf das Argument -b. Die Manpage sagt, dass es "kurz" bedeutetDo not prepend filenames to output lines
craq
1
Es ist nicht erforderlich, die Dateiausgabe zu analysieren, file -b --mime-encoding
sondern
-b steht für 'kurz sein', was im Grunde bedeutet, dass Sie den gerade angegebenen Dateinamen nicht ausgeben.
Nikos
36

uchardet - Eine von Mozilla portierte Codierungsdetektorbibliothek.

Verwendungszweck:

~> uchardet file.java 
UTF-8

Verschiedene Linux-Distributionen (Debian / Ubuntu, OpenSuse-Packman, ...) bieten Binärdateien.

qwert2003
quelle
1
Vielen Dank! Ich freue mich nicht über noch mehr Pakete, aber es sudo apt-get install uchardetist so einfach, dass ich beschlossen habe, mir darüber keine Sorgen zu machen ...
Salbei
Wie ich gerade in einem Kommentar oben sagte: uchardet sagt mir fälschlicherweise, dass die Codierung einer Datei "windows-1252" war, obwohl ich diese Datei explizit als UTF-8 gespeichert habe. uchardet sagt nicht einmal "mit Zuversicht 0.4641618497109827", was Ihnen zumindest einen Hinweis geben würde, dass es Ihnen völligen Unsinn sagt. file, enca und encguess haben korrekt funktioniert.
Algoman
uchardethat einen großen Vorteil gegenüber fileund darin enca, dass es die gesamte Datei analysiert (nur mit einer 20GiB-Datei versucht), im Gegensatz zu nur dem Anfang.
Smoking
10

Hier ist ein Beispielskript mit Datei -I und iconv, das unter MacOsX funktioniert. Für Ihre Frage müssen Sie mv anstelle von iconv verwenden

#!/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
quelle
6
file -b --mime-encodinggibt nur den Zeichensatz aus, so dass Sie jede Pipe-Verarbeitung vermeiden können
jesjimher
1
Vielen Dank. Wie unter MacOS erwähnt, funktioniert dies nicht: Datei -b --mime-encoding Verwendung: Datei [-bchikLNnprsvz0] [-e Test] [-f Name-Datei] [-F Trennzeichen] [-m magische Dateien] [-M magische Dateien ] file ... file -C -m magicfiles Weitere Informationen finden Sie unter "file --help".
Wolfgang Fahl
6

Es ist wirklich schwer festzustellen, ob es sich um ISO-8859-1 handelt. Wenn Sie einen Text mit nur 7-Bit-Zeichen haben, der auch iso-8859-1 sein könnte, aber Sie wissen es nicht. Wenn Sie 8-Bit-Zeichen haben, sind die Zeichen des oberen Bereichs auch in der Reihenfolge der Codierungen vorhanden. Daher müssten Sie ein Wörterbuch verwenden, um besser zu erraten, um welches Wort es sich handelt, und um von dort aus zu bestimmen, welcher Buchstabe es sein muss. Wenn Sie schließlich feststellen, dass es sich möglicherweise um utf-8 handelt, sind Sie sicher, dass es sich nicht um iso-8859-1 handelt

Das Codieren ist eines der schwierigsten Dinge, weil Sie nie wissen, ob Ihnen nichts sagt

Norbert Hartl
quelle
Es kann hilfreich sein, brutale Gewalt zu versuchen. Der folgende Befehl versucht, alle Ecncoding-Formate mit Namen, die mit WIN oder ISO beginnen, in UTF8 zu konvertieren. Dann müsste man die Ausgabe manuell überprüfen und nach einem Hinweis auf die richtige Codierung suchen. Natürlich können Sie die gefilterten Formate ändern, indem Sie ISO oder WIN durch etwas Passendes ersetzen, oder den Filter entfernen, indem Sie den Befehl grep entfernen. für i in $ (iconv -l | tail -n +2 | grep "(^ ISO \ | ^ WIN)" | sed -es / \ / \ /// '); Echo $ i; iconv -f $ i -t UTF8 santos; getan;
ndvo
5

In Debian können Sie auch: encguess:

$ encguess test.txt
test.txt  US-ASCII
not2qubit
quelle
Ich habe uchardetin Ubuntu installiert und es hat mir gesagt, dass meine Datei war WINDOWS-1252. Ich weiß, dass dies falsch war, weil ich es mit Kate als UTF-16 gespeichert habe, um es zu testen. Allerdings encguessdenkt , richtig, und es wurde in Ubuntu 19.04 vorinstalliert.
Nagev
5

So konvertieren Sie die Codierung von 8859 in ASCII:

iconv -f ISO_8859-1 -t ASCII filename.txt
Fimbulwinter
quelle
4

Mit Python können Sie das Chardet-Modul verwenden: https://github.com/chardet/chardet

fccoelho
quelle
Nicht existierende Domain: feedparser.org
Rune
Ab diesem Kommentar ist es noch auf Github verfügbar: github.com/dcramer/chardet
Rick Hanlon II
Ab diesem Kommentar ist es auf Chardet / Chardet auf Github. Antwort aktualisiert.
Quentin Pradet
chardet Berichte „None“, chardet3 würgt in der ersten Zeile der Datei in der exakt gleichen Art und Weise , dass mein Python - Skript tut.
Joels Elf
3

Dies können Sie nicht kinderleicht tun. Eine Möglichkeit wäre, jedes Zeichen in der Datei zu prüfen , um sicherzustellen , dass es keine Zeichen enthält in den Bereichen 0x00 - 0x1foder 0x7f -0x9faber, wie gesagt, dies mag wahr sein , für eine beliebige Anzahl von Dateien, einschließlich mindestens einer anderen Variante von ISO8859.

Eine andere Möglichkeit besteht darin, in allen unterstützten Sprachen nach bestimmten Wörtern in der Datei zu suchen und zu prüfen, ob Sie sie finden können.

Suchen Sie beispielsweise in allen unterstützten Sprachen von 8859-1 das Äquivalent von Englisch "und", "aber", "zu", "von" usw. und prüfen Sie, ob sie eine große Anzahl von Vorkommen in der Sprache enthalten Datei.

Ich spreche nicht von wörtlicher Übersetzung wie:

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

obwohl das möglich ist. Ich spreche über gebräuchliche Wörter in der Zielsprache (nach allem, was ich weiß, hat Isländisch kein Wort für "und" - Sie müssten wahrscheinlich ihr Wort für "Fisch" verwenden [Entschuldigung, das ist ein wenig stereotyp, habe ich nicht meine jede Straftat, nur um einen Punkt zu veranschaulichen]).

paxdiablo
quelle
2

Ich weiß, dass Sie an einer allgemeineren Antwort interessiert sind, aber was in ASCII gut ist, ist normalerweise in anderen Codierungen gut. Hier ist ein Python-Einzeiler, um festzustellen, ob die Standardeingabe ASCII ist. (Ich bin mir ziemlich sicher, dass dies in Python 2 funktioniert, aber ich habe es nur auf Python 3 getestet.)

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
quelle
2

Wenn es sich um XML-Dateien handelt (ISO-8859-1), gibt die darin enthaltene XML-Deklaration die Codierung an: <?xml version="1.0" encoding="ISO-8859-1" ?>
Sie können also reguläre Ausdrücke (z. B. mit perl) verwenden, um jede Datei auf eine solche Spezifikation zu überprüfen.
Weitere Informationen finden Sie hier: So bestimmen Sie die Codierung von Textdateien .

evgeny9
quelle
Nun, diese Zeile könnte von jemandem kopiert und eingefügt werden, der nicht weiß, welche Codierung er verwendet.
Algoman
Achtung, nichts an der Deklaration oben garantiert, dass die Datei WIRKLICH auf diese Weise codiert ist. Wenn Sie sich wirklich für die Codierung interessieren, müssen Sie sie selbst validieren.
Jazzepi
2

In PHP können Sie wie folgt überprüfen:

Codierungsliste explizit angeben:

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

Genauere "mb_list_encodings":

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

Hier im ersten Beispiel können Sie sehen, dass ich eine Liste von Codierungen (Listenreihenfolge erkennen) eingefügt habe, die möglicherweise übereinstimmen. Um ein genaueres Ergebnis zu erhalten, können Sie alle möglichen Codierungen verwenden über: mb_list_encodings ()

Hinweis mb_ * -Funktionen erfordern php-mbstring

apt-get install php-mbstring
Mohamed23gharbi
quelle
0

In Cygwin sieht das so aus, als würde es bei mir funktionieren:

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

Beispiel:

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

Sie können dies an awk weiterleiten und einen iconv-Befehl erstellen, um alles von jeder von iconv unterstützten Quellcodierung in utf8 zu konvertieren.

Beispiel:

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
quelle
0

Sie können die Codierung einer einzelnen Datei mit dem Befehl file extrahieren. Ich habe eine sample.html-Datei mit:

$ file sample.html 

sample.html: HTML-Dokument, UTF-8-Unicode-Text mit sehr langen Zeilen

$ file -b sample.html

HTML-Dokument, UTF-8-Unicode-Text, mit sehr langen Zeilen

$ file -bi sample.html

Text / HTML; Zeichensatz = utf-8

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

utf-8

Daniel Faure
quelle
1
Die Ausgabe, die ich bekomme, ist nur "reguläre Datei"
Mordechai
0

Ich benutze das folgende Skript um

  1. Suchen Sie alle Dateien, die FILTER mit SRC_ENCODING übereinstimmen
  2. Erstellen Sie eine Sicherungskopie davon
  3. Konvertieren Sie sie in DST_ENCODING
  4. (optional) Entfernen Sie die Backups

.

#!/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
quelle
0

mit diesem Befehl:

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

Sie können alle Dateien in einem Verzeichnis und Unterverzeichnissen sowie die entsprechende Codierung auflisten.

Danilo
quelle
-2

Verwenden Sie in Perl Encode :: Detect.

manu_v
quelle
7
Können Sie ein Beispiel geben, wie es in der Shell verwendet wird?
Lri
Ein anderes Poster (@fccoelho) lieferte ein Python-Modul als Lösung, das eine +3 erhält, und dieses Poster erhält eine -2 für eine sehr ähnliche Antwort, außer dass es sich um ein Perl-Modul handelt. Warum die Doppelmoral?!
Happy Green Kid Nickerchen
4
Vielleicht würde ein Codebeispiel eines Perl-Einzeilers diese Antwort unterstützen.
Wikingersteve