Jak znaleźć kodowanie pliku za pomocą skryptu w systemie Linux?

303

Muszę znaleźć kodowanie wszystkich plików umieszczonych w katalogu. Czy istnieje sposób na znalezienie zastosowanego kodowania?

fileKomenda nie jest w stanie tego zrobić.

Interesujące mnie kodowanie to: ISO-8859-1. Jeśli kodowanie jest czymś innym, chcę przenieść plik do innego katalogu.

Manglu
źródło
1
Jeśli masz pomysł, jakiego języka skryptowego możesz użyć, oznacz swoje pytanie nazwą tego języka. To może pomóc ...
MatrixFrog,
1
A może po prostu próbuje zbudować skrypt powłoki?
Shalom Craimer
1
Co byłoby odpowiedzią na „który język skryptowy”.
bignose
7
Może nie związane z tą odpowiedzią, ale ogólnie wskazówka: kiedy możesz opisać całą swoją wątpliwość jednym słowem („kodowanie” tutaj), po prostu zrób apropos encoding. Przeszukuje tytuły i opisy wszystkich stron. Kiedy zrobić to na moim komputerze, widzę 3 narzędzia, które może mi pomóc, sądząc po ich opisy: chardet, chardet3, chardetect3. Następnie, robiąc man chardeti czytając stronę podręcznika, mówi mi, że chardetto tylko narzędzie, którego potrzebuję.
John Red,
1
Kodowanie może ulec zmianie po zmianie zawartości pliku. np. w vi, kiedy piszesz prosty program c, jest to prawdopodobnie us-ascii, ale po dodaniu wiersza chińskiego komentarza staje się utf-8. filerozpoznaje kodowanie, czytając treść pliku i zgadnij.
Eric Wang,

Odpowiedzi:

419

Wygląda na to, że szukasz enca. Może zgadywać, a nawet konwertować między kodowaniami. Wystarczy spojrzeć na stronę podręcznika .

Lub, jeśli to nie pomoże, użyj file -i(linux) lub file -I(osx). Spowoduje to wyświetlenie informacji typu MIME dla pliku, która będzie również zawierać kodowanie zestawu znaków. Znalazłem też stronę dla niego :)

Shalom Craimer
źródło
1
Według strony podręcznika wie o zestawie ISO 8559. Być może przeczytaj trochę mniej kursywnie :-)
bignose
5
Enca brzmi interesująco. Niestety wykrywanie wydaje się być bardzo zależne od języka, a zestaw obsługiwanych języków nie jest zbyt duży. Brakuje
mojego
1
Dobry post na temat narzędzi takich jak enca, enconv, convmv
GuruM,
6
encawydaje się całkowicie bezużyteczny do analizy pliku napisanego w języku angielskim, ale jeśli zdarzy ci się patrzeć na coś w języku estońskim, może to rozwiązać wszystkie twoje problemy. Bardzo pomocne narzędzie, które ... </sarcasm>
cbmanica 16.04.13
6
@vladkras, jeśli w twoim pliku utf-8 nie ma znaków innych niż ascii, to nie można go odróżnić od ascii :)
vadipp
85
file -bi <file name>

Jeśli chcesz to zrobić dla wielu plików

for f in `find | egrep -v Eliminate`; do echo "$f" ' -- ' `file -bi "$f"` ; done
madu
źródło
Jeśli jednak plik jest plikiem XML, z atrybutem „encoding = 'iso-8859-1” w deklaracji xml, polecenie file powie, że jest to plik ISO, nawet jeśli prawdziwym kodowaniem jest utf-8 ...
Za
6
Dlaczego używasz argumentu -b? Jeśli tylko zrobisz plik -i *, wyświetli on odgadnięty zestaw znaków dla każdego pliku.
Hans-Peter Störr
4
Byłem też ciekawy argumentu -b. Strona Do not prepend filenames to output lines
podręcznika
1
Nie trzeba analizować danych wyjściowych pliku, file -b --mime-encodingwyprowadza tylko kodowanie zestawu znaków
jesjimher
-b oznacza „bądź krótki”, co w zasadzie oznacza, że ​​nie wypisuj podanej nazwy pliku.
Nikos
36

uchardet - biblioteka wykrywaczy kodowania przeniesiona z Mozilli.

Stosowanie:

~> uchardet file.java 
UTF-8

Różne dystrybucje Linuksa (Debian / Ubuntu, OpenSuse-packman, ...) zapewniają pliki binarne.

qwert2003
źródło
1
Dzięki! Nie jestem zachwycony kolejnymi pakietami, ale sudo apt-get install uchardetjest to tak łatwe, że postanowiłem się tym nie martwić ...
mędrzec
Jak właśnie powiedziałem w powyższym komentarzu: uchardet fałszywie mówi mi, że kodowanie pliku to „windows-1252”, chociaż jawnie zapisałem ten plik jako UTF-8. uchardet nawet nie mówi „z pewnością 0.4641618497109827”, co przynajmniej dałoby ci wskazówkę, że mówi ci kompletne bzdury. file, enca i encguess działały poprawnie.
Algoman
uchardetma dużą przewagę nad filei enca, w który analizuje cały plik (tylko próbował z plikiem 20GiB), w przeciwieństwie do tylko początek.
tuxayo
10

oto przykładowy skrypt wykorzystujący plik -I i iconv, który działa na MacOsX. W swoim pytaniu musisz użyć mv zamiast 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
źródło
6
file -b --mime-encodingwyprowadza tylko
zestaw
1
Dzięki. Jak wskazano w systemie MacOS, to nie zadziała: plik -b - kodowanie-mime Użycie: plik [-bchikLNnprsvz0] [-e test] [-f nazwa_pliku] [-F separator] [-m pliki-magiczne] [-M pliki-magiczne ] plik ... plik -C -m magicfiles Wypróbuj `file --help ', aby uzyskać więcej informacji.
Wolfgang Fahl
6

Naprawdę trudno jest ustalić, czy jest to iso-8859-1. Jeśli masz tekst składający się tylko z 7 znaków bitowych, którym może być również iso-8859-1, ale nie wiesz. Jeśli masz 8 bitów, znaki górnego regionu również występują w kodowaniu kolejności. Dlatego musiałbyś użyć słownika, aby lepiej odgadnąć, jakie to słowo i ustalić, która to litera. Wreszcie, jeśli wykryjesz, że może to być utf-8, to masz pewność, że nie jest to iso-8859-1

Kodowanie jest jedną z najtrudniejszych rzeczy do zrobienia, ponieważ nigdy nie wiadomo, czy nic ci nie mówi

Norbert Hartl
źródło
Może pomóc próba brutalnej siły. Następujące polecenie spróbuje przekonwertować ze wszystkich formatów eknkodowania o nazwach rozpoczynających się od WIN lub ISO na UTF8. Następnie należałoby ręcznie sprawdzić dane wyjściowe, szukając wskazówki na temat właściwego kodowania. Oczywiście możesz zmienić filtrowane formaty zastępując ISO lub WIN na coś odpowiedniego lub usunąć filtr, usuwając polecenie grep. dla i w $ (iconv -l | tail -n +2 | grep "(^ ISO \ | ^ WIN)" | sed -e 's / \ / \ ///'); wykonaj echo $ i; iconv -f $ i -t Santos UTF8; Gotowe;
ndvo
5

W Debianie możesz także użyć encguess:

$ encguess test.txt
test.txt  US-ASCII
not2qubit
źródło
Zainstalowałem uchardetw Ubuntu i powiedział mi, że mój plik to WINDOWS-1252. Wiem, że to było złe, ponieważ zapisałem go jako UTF-16 z Kate, aby przetestować. Jednak encguesszgadnij poprawnie i został on wstępnie zainstalowany w Ubuntu 19.04.
Nagev
5

Aby przekonwertować kodowanie z 8859 na ASCII:

iconv -f ISO_8859-1 -t ASCII filename.txt
fimbulwinter
źródło
4

W Pythonie możesz użyć modułu chardet: https://github.com/chardet/chardet

fccoelho
źródło
Nieistniejąca domena: feedparser.org
Rune
Według tego komentarza jest on nadal dostępny na Github: github.com/dcramer/chardet
Rick Hanlon II
Od tego komentarza jest na chardet / chardet na github. Zaktualizowana odpowiedź.
Quentin Pradet
chardet zgłasza „Brak”, dusi chardet3 w pierwszym wierszu pliku w dokładnie taki sam sposób, jak robi to mój skrypt python.
Joels Elf
3

Nie można tego zrobić w niezawodny sposób. Jedną z możliwości byłoby zbadać każdy znak w pliku, aby upewnić się, że nie zawiera żadnych znaków w zakresach 0x00 - 0x1fczy 0x7f -0x9f, ale jak powiedziałem, to może być prawdziwe dla dowolnej liczby plików, w tym co najmniej jednego innego wariantu ISO8859.

Inną możliwością jest poszukiwanie określonych słów w pliku we wszystkich obsługiwanych językach i sprawdzenie, czy możesz je znaleźć.

Na przykład znajdź odpowiednik angielskiego „i”, „ale”, „do”, „z” itd. We wszystkich obsługiwanych językach 8859-1 i sprawdź, czy występuje w nich duża liczba wystąpień plik.

Nie mówię o dosłownym tłumaczeniu, takim jak:

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

chociaż to możliwe. Mówię o popularnych słowach w języku docelowym (z tego co wiem, islandzki nie ma słowa na „i” - prawdopodobnie będziesz musiał użyć ich słowa na „ryba” [przepraszam, to trochę stereotypowe, nie zrobiłem tego oznacza każde przestępstwo, ilustrujące tylko punkt]).

paxdiablo
źródło
2

Wiem, że interesuje Cię bardziej ogólna odpowiedź, ale to, co jest dobre w ASCII, jest zwykle dobre w innych kodowaniach. Oto jedno-liniowy Python, który określa, czy standardowym wejściem jest ASCII. (Jestem pewien, że to działa w Pythonie 2, ale przetestowałem to tylko w Pythonie 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
źródło
2

Jeśli mówisz o plikach XML (ISO-8859-1), deklaracja XML w nich określa kodowanie: <?xml version="1.0" encoding="ISO-8859-1" ?>
Możesz więc użyć wyrażeń regularnych (np. Z perl), aby sprawdzić każdy plik pod kątem takiej specyfikacji.
Więcej informacji można znaleźć tutaj: Jak ustalić kodowanie pliku tekstowego .

evgeny9
źródło
cóż, ten wiersz może zostać skopiowany i wklejony przez kogoś, kto nie wie, jakiego kodowania używa.
Algoman
Uwaga: nic na temat deklaracji na górze nie gwarantuje, że plik faktycznie zostanie zakodowany w ten sposób. Jeśli naprawdę zależy ci na kodowaniu, musisz je samodzielnie zweryfikować.
Jazzepi,
2

W php możesz sprawdzić jak poniżej:

Określając jawnie listę kodowania:

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

Dokładniejsze „mb_list_encodings”:

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

Tutaj w pierwszym przykładzie widać, że umieściłem listę kodowań (wykryj kolejność list), które mogą być zgodne. Aby uzyskać dokładniejszy wynik, możesz użyć wszystkich możliwych kodowań poprzez: mb_list_encodings ()

Uwaga: funkcje mb_ * wymagają php-mbstring

apt-get install php-mbstring
Mohamed23gharbi
źródło
0

W Cygwin wygląda to tak, jak dla mnie działa:

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

Przykład:

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

Możesz potokować to do awk i utworzyć polecenie iconv, aby przekonwertować wszystko na utf8, z dowolnego kodowania źródłowego obsługiwanego przez iconv.

Przykład:

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
źródło
0

Możesz wyodrębnić kodowanie pojedynczego pliku za pomocą polecenia file. Mam plik sample.html z:

$ file sample.html 

sample.html: dokument HTML, tekst UTF-8 Unicode, z bardzo długimi liniami

$ file -b sample.html

Dokument HTML, tekst UTF-8 Unicode, z bardzo długimi liniami

$ file -bi sample.html

text / html; charset = utf-8

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

utf-8

Daniel Faure
źródło
1
wyniki, które otrzymuję, to po prostu „zwykły plik”
Mordechai,
0

Używam następującego skryptu do

  1. Znajdź wszystkie pliki pasujące do FILTER z SRC_ENCODING
  2. Utwórz ich kopię zapasową
  3. Konwertuj je na DST_ENCODING
  4. (opcjonalnie) Usuń kopie zapasowe

.

#!/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
źródło
0

za pomocą tego polecenia:

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

możesz wyświetlić listę wszystkich plików w katalogu i podkatalogach oraz odpowiadające im kodowanie.

Danilo
źródło
-2

W Perlu użyj Encode :: Detect.

manu_v
źródło
7
Czy możesz podać przykład użycia go w powłoce?
Lri
Inny plakat (@fccoelho) dostarczył moduł Pythona jako rozwiązanie, które otrzymuje +3, a ten plakat otrzymuje -2 za bardzo bardzo podobną odpowiedź, z wyjątkiem tego, że dotyczy modułu Perla. Dlaczego podwójny standard ?!
Happy Green Kid Naps
4
Być może kodowy przykład linijki perlowej pomógłby w tej odpowiedzi.
vikingsteve,