Як знайти кодування файлу за допомогою скрипту в Linux?


303

Мені потрібно знайти кодування всіх файлів, які розміщені в каталозі. Чи є спосіб знайти кодування?

fileКоманда не в змозі зробити це.

Кодування, яке мене цікавить: ISO-8859-1. Якщо кодування є чимось іншим, я хочу перенести файл в інший каталог.


1
Якщо у вас є уявлення про те, якою мовою сценарію ви хочете скористатися, позначте своє питання назвою цієї мови. Це може допомогти ...
MatrixFrog

1
А може, він просто намагається створити сценарій оболонки?
Шалом Креймер

1
Що було б відповіддю на "яку мову сценаріїв".
bignose

7
Можливо, не пов’язана з цією відповіддю, але підказка взагалі: Коли ви можете описати весь сумнів одним словом («кодування», тут), просто зробіть apropos encoding. Він шукає заголовки та описи всіх рукописів. Коли я роблю це на моїй машині, я бачу 3 інструментів , які могли б допомогти мені, судячи з їх описами: chardet, chardet3, chardetect3. Потім, роблячи man chardetта читаючи manpage, мені кажуть, що я chardetпросто потрібна програма.
Джон Ред

1
Кодування може змінитися, коли ви зміните вміст файлу. Наприклад, коли vi, коли пишеш просту програму c, це, мабуть us-ascii, але після додавання рядка з коментарями з Китаю, це стає utf-8. fileможе сказати кодування, прочитавши вміст файлу та здогадатися.
Ерік Ван

Відповіді:


419

Здається, ви шукаєте enca. Він може здогадуватися і навіть конвертувати між кодуванням. Просто подивіться на сторінку чоловіка .

Або, якщо цього не зробити, використовуйте file -i(linux) або file -I(osx). Це буде виводити інформацію типу MIME для файлу, яка також буде включати кодування набору символів. Я знайшов іменну сторінку для цього теж :)


1
За повідомленням людини, він знає про набір ISO 8559. Можливо, читайте трохи менш пильно :-)
bignose

5
Енка звучить цікаво. На жаль, виявлення дуже залежить від мови, а набір підтримуваних мов не дуже великий. Міна (де) відсутня :-( Як би то не було класний інструмент.
er4z0r

1
Хороший пост на таких інструментах, як enca, enconv, convmv
GuruM

6
encaвидається абсолютно марним для аналізу файлу, написаного англійською мовою, але якщо вам трапляється дивитись на щось естонською, це може вирішити всі ваші проблеми. Дуже корисний інструмент, що ... </sarcasm>
cbmanica

6
@vladkras, якщо у вашому файлі utf-8 немає символів, що не відносяться до ascii, то це не відрізняється від ascii :)
vadipp

85
file -bi <file name>

Якщо ви хочете зробити це для купки файлів

for f in `find | egrep -v Eliminate`; do echo "$f" ' -- ' `file -bi "$f"` ; done

Однак, якщо файл - це файл XML, з атрибутом "encoding = 'iso-8859-1" у оголошенні xml, команда файлу скаже, що це файл iso, навіть якщо справжнє кодування є utf-8 ...
За

6
Чому ви використовуєте аргумент -b? Якщо ви просто зробите файл -i *, він виводить відгадану діаграму для кожного файлу.
Ганс-Пітер Штерр

4
Мені було цікаво і аргумент -b. Сторінка чоловіка говорить, що це означає "коротко"Do not prepend filenames to output lines
craq

1
Немає необхідності аналізувати вихід файлів, file -b --mime-encodingвиводить лише кодування
шаблонів

-b означає «бути коротким», що в основному означає не виводити ім’я файлу, яке ви тільки що дали.
Нікос

36

учардеть - Бібліотека детекторів кодування, перенесена з Mozilla.

Використання:

~> uchardet file.java 
UTF-8

Різні дистрибутиви Linux (Debian / Ubuntu, OpenSuse-packman, ...) надають бінарні файли.


1
Дякую! Я не в захваті від ще більшої кількості пакетів, але sudo apt-get install uchardetвсе так просто, що я вирішив не хвилюватися з цього приводу ...
мудрець

Як я щойно сказав у коментарі вище: uchardet помилково повідомляє, що кодування файлу було "windows-1252", хоча я явно зберігав цей файл як UTF-8. uchardet навіть не каже "з упевненістю 0.4641618497109827", що хоч би дало вам натяк на те, що воно говорить вам про повну нісенітницю. Файл, енка та інгус працювали правильно.
Алгоман

uchardetмає велику перевагу перед fileі encaв тому , що він аналізує весь файл (просто намагався з файлом 20GiB) в протилежність тільки початок.
tuxayo

10

ось приклад сценарію з використанням файлу -I та iconv, який працює на MacOsX. Для вашого питання вам потрібно використовувати mv замість 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

6
file -b --mime-encodingвиводить лише шаблони, тому ви можете уникнути всієї обробки труб
jesjimher

1
Дякую. Як зазначалося в MacOS, це не працюватиме: файл -b - кодування часу, використання: файл [-bchikLNnprsvz0] [-e тест] [-f namefile] [-F separator] [-m magicfiles] [-M magicfiles ] file ... file -C -m magicfiles Спробуйте `файл --help 'для отримання додаткової інформації.
Вольфганг Фаль

6

Справді важко визначити, чи це iso-8859-1. Якщо у вас є текст із лише 7-бітовими символами, який також може бути iso-8859-1, але ви цього не знаєте. Якщо у вас є 8-бітові символи, знаки верхньої області також існують у порядку кодування. Для цього вам доведеться скористатися словником, щоб краще здогадатися, яке це слово, і звідти визначити, якою буквою воно повинно бути. Нарешті, якщо ви виявите, що це може бути utf-8, ніж ви впевнені, що це не iso-8859-1

Кодування - одна з найскладніших речей, оскільки ти ніколи не знаєш, чи нічого тобі не підказує


Це може допомогти спробувати грубу силу. Наступна команда спробує перетворити з усіх форматів ecncoding з іменами, які починаються з WIN або ISO, в UTF8. Тоді потрібно буде вручну перевірити вихід, шукаючи підказку в правильному кодуванні. Звичайно, ви можете змінити відфільтровані формати замінюючи ISO або WIN на щось відповідне або видалити фільтр, видаливши команду grep. для i в $ (iconv -l | хвіст -n +2 | grep "(^ ISO \ | ^ WIN)" | sed -e 's / \ / \ ///'); робити відлуння $ i; iconv -f $ i -t UTF8 santos; зроблено;
ndvo

5

У Debian ви також можете використовувати encguess:

$ encguess test.txt
test.txt  US-ASCII

Я встановив uchardetв Ubuntu, і мені сказали, що мій файл WINDOWS-1252. Я знаю, що це було неправильно, тому що я зберег його як UTF-16 разом з Kate, щоб перевірити. Однак encguessвідгадайте правильно, і він був попередньо встановлений в Ubuntu 19.04.
Нагев

5

Для перетворення кодування з 8859 в ASCII:

iconv -f ISO_8859-1 -t ASCII filename.txt

4

За допомогою Python ви можете використовувати модуль chardet: https://github.com/chardet/chardet


Неіснуючий домен: feedparser.org
Руна

Щодо цього коментаря, він все ще доступний у Github: github.com/dcramer/chardet
Rick Hanlon II

Що стосується цього коментаря, він знаходиться на chardet / chardet на github. Оновлена ​​відповідь.
Квентін Прадет

chardet повідомляє "None", chardet3 задавлюється в першому рядку файлу точно так само, як і мій скрипт python.
Joels Elf

3

Це не те, що можна зробити безглуздо. Однією з можливостей було б вивчити кожен символ у файлі, щоб переконатися, що він не містить символів у діапазонах 0x00 - 0x1fабо0x7f -0x9f , але, як я вже сказав, це може бути вірно для будь-якої кількості файлів, в тому числі , щонайменше , одного іншого варіанту ISO8859.

Інша можливість полягає у пошуку конкретних слів у файлі на всіх підтримуваних мовах та перевірте, чи можете ви їх знайти.

Так, наприклад, знайдіть еквівалент англійських "і", "але", "до", "з" і так далі в усіх підтримуваних мовах 8859-1 і перевірте, чи є в них велика кількість зустрічань в межах файл.

Я не говорю про буквальний переклад, наприклад:

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

хоча це можливо. Я говорю про загальні слова цільовою мовою (наскільки я знаю, в ісландській мові немає слова "і" - ви, мабуть, повинні використовувати їх слово для "риби" [вибачте, це трохи стереотипно, я не означають будь-яке правопорушення, просто ілюструючи точку]).


2

Я знаю, що вас цікавить більш загальна відповідь, але те, що добре в ASCII, як правило, добре в інших кодуваннях. Ось одноклапник Python, щоб визначити, чи є стандартним входом ASCII. (Я впевнений, що це працює в Python 2, але я протестував це лише на 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

2

Якщо ви говорите про XML-файли (ISO-8859-1), декларація XML всередині них вказує кодування: <?xml version="1.0" encoding="ISO-8859-1" ?>
Отже, ви можете використовувати регулярні вирази (наприклад, з perl), щоб перевірити кожен файл на таку специфікацію.
Додаткову інформацію можна знайти тут: Як визначити кодування текстових файлів .


добре, що цей рядок може бути скопійовано копійованим n-тим, хто не знає, яке кодування він використовує.
Алгоман

Обережно, нічого про декларацію вгорі не гарантує, що файл АКТУАЛЬНО кодується таким чином. Якщо вам дійсно дуже важливо кодування, вам потрібно перевірити його самостійно.
Jazzepi

2

У php ви можете перевірити як нижче:

Вказання списку кодування явно:

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":

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

Тут у першому прикладі ви бачите, що я помістив список кодувань (порядок виявлення списку), які можуть відповідати. Для отримання більш точного результату ви можете використовувати всі можливі кодування через: mb_list_encodings ()

Примітка. Функції mb_ * вимагають php-mbstring

apt-get install php-mbstring

0

У Cygwin це виглядає так, як це працює для мене:

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

Приклад:

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

Ви можете передати цю проблему і створити команду iconv, щоб перетворити все в utf8, з будь-якого джерельного кодування, що підтримується iconv.

Приклад:

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

0

Ви можете витягнути кодування одного файлу за допомогою команди file. У мене є sample.html файл із:

$ file sample.html 

sample.html: HTML-документ, UTF-8 Unicode-текст, з дуже довгими рядками

$ file -b sample.html

HTML-документ, текст UTF-8 Unicode, з дуже довгими рядками

$ file -bi sample.html

текст / html; charset = utf-8

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

utf-8


1
вихід, який я отримую, є просто "звичайним файлом"
Мордехай,

0

Я використовую наступний сценарій для

  1. Знайдіть усі файли, які відповідають FILTER та SRC_ENCODING
  2. Створіть резервну копію з них
  3. Перетворити їх у DST_ENCODING
  4. (необов’язково) Видаліть резервні копії

.

#!/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 {} \;

0

з цією командою:

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

Ви можете перелічити всі файли в каталозі та підкаталогах та відповідне кодування.


-2

За допомогою Perl використовуйте Encode :: Detect.


7
Чи можете ви навести приклад, як його використовувати в оболонці?
Лрі

Інший плакат (@fccoelho) надав модуль Python як рішення, яке отримує +3, і цей плакат отримує -2 за дуже схожу відповідь, за винятком того, що це для модуля Perl. Чому подвійний стандарт ?!
Happy Green Kid Naps

4
Можливо, приклад коду однорівневого Perl допоможе в цьому відповіді.
vikingsteve
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.