Как найти кодировку файла через скрипт в Linux?

303

Мне нужно найти кодировку всех файлов, которые размещены в каталоге. Есть ли способ найти используемую кодировку?

Команда fileне может сделать это.

Интересующая меня кодировка: ISO-8859-1. Если кодировка является чем-то еще, я хочу переместить файл в другой каталог.

Manglu
источник
1
Если у вас есть представление о том, какой язык сценариев вы хотите использовать, пометьте свой вопрос названием этого языка. Это может помочь ...
MatrixFrog
1
Или, может быть, он просто пытается создать сценарий оболочки?
Шалом Креймер
1
Какой будет ответом на «какой язык сценариев».
bignose
7
Может быть, не связано с этим ответом, но совет в целом: когда вы можете описать все ваши сомнения в одном слове («кодировка», здесь), просто сделайте apropos encoding. Он ищет названия и описания всех справочных страниц. Когда я делаю это на моей машине, я вижу 3 инструментов , которые могли бы помочь мне, судя по их описаниям: chardet, chardet3, chardetect3. Затем, man chardetпрочитав man-страницу, вы узнаете, что 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
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, команда file скажет, что это iso-файл, даже если истинная кодировка - utf-8 ...
За
6
Почему вы используете аргумент -b? Если вы просто делаете файл -i *, он выводит угаданную кодировку для каждого файла.
Ханс-Петер Стёрр
4
Мне было любопытно и аргумент -b. Страница man говорит, что это означает "кратко"Do not prepend filenames to output lines
craq
1
Нет необходимости анализировать вывод файла, file -b --mime-encodingвыводит только кодировку charset
jesjimher
-b означает «быть кратким», что в основном означает не выводить имя файла, которое вы только что дали.
Никос
36

uchardet - библиотека детекторов кодирования, портированная из Mozilla.

Использование:

~> uchardet file.java 
UTF-8

Различные дистрибутивы Linux (Debian / Ubuntu, OpenSuse-packman, ...) предоставляют двоичные файлы.

qwert2003
источник
1
Спасибо! Я не в восторге от еще большего количества пакетов, но sudo apt-get install uchardetнастолько легко, что я решил не беспокоиться об этом ...
Мудрец
Как я только что сказал в комментарии выше: uchardet ложно говорит мне, что кодировка файла была «windows-1252», хотя я явно сохранил этот файл как UTF-8. Учардет даже не говорит «с уверенностью 0.4641618497109827», что, по крайней мере, даст вам подсказку, что это говорит вам полную чушь. Файл, Enca и Encguess работали правильно.
Algoman
uchardetимеет большое преимущество по сравнению fileс тем enca, что анализирует весь файл (только что попробованный с файлом 20 ГБ), а не только начало.
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выводит только кодировку, так что вы можете избежать обработки всех
каналов
1
Спасибо. Как указано в MacOS, это не будет работать: file -b - mime-encoding Использование: file [-bchikLNnprsvz0] [-e test] [-f namefile] [-F separator] [-m magicfiles] [-M magicfiles ] file ... file -C -m magicfiles Попробуйте `file --help 'для получения дополнительной информации.
Вольфганг Фаль
6

Это действительно трудно определить, является ли это iso-8859-1. Если у вас есть текст только с 7-битными символами, который также может быть iso-8859-1, но вы не знаете. Если у вас есть 8-битные символы, то символы верхнего региона существуют и в кодировках заказа. Поэтому вам придется использовать словарь, чтобы лучше угадать, какое это слово, и определить, от какой буквы это должно быть. Наконец, если вы обнаружите, что это может быть utf-8, чем вы уверены, что это не iso-8859-1

Кодирование - одна из самых сложных вещей, потому что вы никогда не знаете, ничего не говорит вам

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

В Debian вы также можете использовать encguess:

$ encguess test.txt
test.txt  US-ASCII
not2qubit
источник
Я установил uchardetв Ubuntu, и он сказал мне, что мой файл был WINDOWS-1252. Я знаю, что это было неправильно, потому что я сохранил это как UTF-16 с Кейт, чтобы проверить. Однако, encguessугадайте правильно, и он был предварительно установлен в Ubuntu 19.04.
Нагев
5

Чтобы преобразовать кодировку из 8859 в ASCII:

iconv -f ISO_8859-1 -t ASCII filename.txt
фимбулвинтер
источник
4

С Python вы можете использовать модуль chardet: https://github.com/chardet/chardet

fccoelho
источник
Несуществующий домен: feedparser.org
Rune
Что касается этого комментария, он все еще доступен на Github: github.com/dcramer/chardet
Рик Хэнлон II,
Что касается этого комментария, он находится на chardet / chardet на github. Обновленный ответ.
Квентин Прадет
chardet сообщает "None", chardet3 задыхается в первой строке файла точно так же, как мой скрипт на python.
Джоэлс Эльф
3

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

Другой возможностью является поиск определенных слов в файле на всех поддерживаемых языках и возможность их найти.

Так, например, найдите эквивалент английского «и», «но», «к», «of» и т. Д. На всех поддерживаемых языках 8859-1 и посмотрите, есть ли у них большое количество вхождений в пределах файл.

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

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

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

paxdiablo
источник
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
wkschwartz
источник
2

Если вы говорите о XML-файлах (ISO-8859-1), XML-объявление внутри них определяет кодировку: <?xml version="1.0" encoding="ISO-8859-1" ?>
так что вы можете использовать регулярные выражения (например, с perl), чтобы проверить каждый файл на предмет такой спецификации.
Более подробную информацию можно найти здесь: Как определить кодировку текстового файла .

evgeny9
источник
хорошо, что эта строка может быть скопирована без предупреждения кем-то, кто не знает, какую кодировку он использует.
Algoman
Предостережение, ничто в объявлении вверху не гарантирует, что файл фактически закодирован таким образом. Если вы действительно, действительно заботитесь о кодировке, вам нужно проверить ее самостоятельно.
Джазепи
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
Mohamed23gharbi
источник
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

Вы можете передать это в awk и создать команду 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
skeetastax
источник
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; кодировка = 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.

manu_v
источник
7
Можете ли вы привести пример, как использовать его в оболочке?
Lri
Другой постер (@fccoelho) предоставил модуль Python в качестве решения, которое получает +3, и этот постер получает -2 для очень очень похожего ответа, за исключением того, что это для модуля Perl. Почему двойной стандарт ?!
Happy Green Kid Naps
4
Возможно, пример кода однострочного perl поможет этому ответу.
Викингстеве