Як знайти кодування файлу за допомогою скрипту в 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.