iconv любая кодировка в UTF-8 - PullRequest
19 голосов
/ 22 марта 2012

Я пытаюсь указать iconv на каталог, и все файлы будут преобразованы в UTF-8 независимо от текущей кодировки

Я использую этот сценарий, но вы должны указать, из какой кодировки вы собираетесь ИЗ.Как я могу сделать так, чтобы он автоматически определял текущую кодировку?

dir_iconv.sh

#!/bin/bash

ICONVBIN='/usr/bin/iconv' # path to iconv binary

if [ $# -lt 3 ]
then
    echo "$0 dir from_charset to_charset"
    exit
fi

for f in $1/*
do
    if test -f $f
    then
        echo -e "\nConverting $f"
        /bin/mv $f $f.old
        $ICONVBIN -f $2 -t $3 $f.old > $f
    else
        echo -e "\nSkipping $f - not a regular file";
    fi
done

терминал

sudo convert/dir_iconv.sh convert/books CURRENT_ENCODING utf8

Ответы [ 7 ]

18 голосов
/ 22 марта 2012

Возможно, вы ищете enca:

Enca - чрезвычайно наивный анализатор кодировки.Он обнаруживает набор символов и кодировку текстовых файлов, а также может конвертировать их в другие кодировки, используя встроенный конвертер или внешние библиотеки и инструменты, такие как libiconv, librecode или cstocs.

В настоящее время он поддерживает белорусский, болгарский,Хорватское, чешское, эстонское, венгерское, латышское, литовское, польское, русское, словацкое, словенское, украинское, китайское и некоторые многобайтовые кодировки независимо от языка.

Обратите внимание, что в общем случае автоопределение текущей кодировкиэто сложный процесс (одна и та же последовательность байтов может быть правильным текстом в нескольких кодировках).enca использует эвристику, основанную на языке, который вы говорите, чтобы обнаружить (чтобы ограничить количество кодировок).Вы можете использовать enconv в для преобразования текстовых файлов в одну кодировку.

10 голосов
/ 01 мая 2012

Вы можете получить то, что вам нужно, используя стандартный файл утилит gnu и awk.Пример:

file -bi .xsession-errors дает мне: "text / plain; charset = us-ascii"

поэтому file -bi .xsession-errors |awk -F "=" '{print $2}' дает мне "us-ascii"

Я используюэто в скриптах примерно так:

CHARSET="$(file -bi "$i"|awk -F "=" '{print $2}')"

if [ "$CHARSET" != utf-8 ]; then

        iconv -f "$CHARSET" -t utf8 "$i" -o outfile

fi
6 голосов
/ 06 ноября 2012

Компиляция всех их. Перейти к dir, создать dir2utf8.sh:

#!/bin/bash
# converting all files in a dir to utf8 

for f in *
do
    if test -f $f then
        echo -e "\nConverting $f"
        CHARSET="$( file -bi "$f"|awk -F "=" '{print $2}')"
        if [ "$CHARSET" != utf-8 ]; then
                iconv -f "$CHARSET" -t utf8 "$f" -o "$f"
        fi
    else
        echo -e "\nSkipping $f - it's a regular file";
    fi
done
4 голосов
/ 03 апреля 2014

Вот мое решение для размещения всех файлов:

#!/bin/bash

apt-get -y install recode uchardet > /dev/null
find "$1" -type f | while read FFN # 'dir' should be changed...
do
    encoding=$(uchardet "$FFN")
    echo "$FFN: $encoding"
    enc=`echo $encoding | sed 's#^x-mac-#mac#'`
    set +x
    recode $enc..UTF-8 "$FFN"
done

https://gist.github.com/demofly/25f856a96c29b89baa32

положить его в convert-dir-to-utf8.sh и запустить:

bash convert-dir-to-utf8.sh /pat/to/my/trash/dir

Обратите внимание, что sed - это обходной путь для кодировок Mac. Многим необычным кодировкам нужны обходные пути, подобные этому.

1 голос
/ 15 октября 2018

Вот мой ответ ... = D


#!/bin/bash

find <YOUR_FOLDER_PATH> -name '*' -type f -exec grep -Iq . {} \; -print0 | 
while IFS= read -r -d $'\0' LINE_FILE; do
    CHARSET=$(uchardet $LINE_FILE)
    echo "Converting ($CHARSET) $LINE_FILE"

    # NOTE: Convert/reconvert to utf8. By Questor
    iconv -f "$CHARSET" -t utf8 "$LINE_FILE" -o "$LINE_FILE"

    # NOTE: Remove "BOM" if exists as it is unnecessary. By Questor
    # [Refs.: https://stackoverflow.com/a/2223926/3223785 ,
    # https://stackoverflow.com/a/45240995/3223785 ]
    sed -i '1s/^\xEF\xBB\xBF//' "$LINE_FILE"

done
# [Refs.: https://justrocketscience.com/post/handle-encodings , 
# https://stackoverflow.com/a/9612232/3223785 , 
# https://stackoverflow.com/a/13659891/3223785 ]

ДАЛЬНЕЙШИЙ ВОПРОС: Я не знаю, является ли мой подход наиболее безопасным. Я говорю это потому, что заметил, что некоторые файлы неправильно конвертированы (символы будут потеряны) или «усечены». Я подозреваю, что это связано с инструментом iconv или с информацией о кодировке, полученной с помощью инструмента uchardet. Мне было интересно узнать о решении, представленном в https://stackoverflow.com/a/22841847/3223785 (@demofly), потому что оно может быть безопаснее.


Другой ответ, теперь основанный на ответе @demofly ...

#!/bin/bash

find <YOUR_FOLDER_PATH> -name '*' -type f -exec grep -Iq . {} \; -print0 | 
while IFS= read -r -d $'\0' LINE_FILE; do
    CHARSET=$(uchardet $LINE_FILE)
    REENCSED=`echo $CHARSET | sed 's#^x-mac-#mac#'`
    echo "\"$CHARSET\" \"$LINE_FILE\""

    # NOTE: Convert/reconvert to utf8. By Questor
    recode $REENCSED..UTF-8 "$LINE_FILE" 2> STDERR_OP 1> STDOUT_OP

    STDERR_OP=$(cat STDERR_OP)
    rm -f STDERR_OP
    if [ -n "$STDERR_OP" ] ; then

        # NOTE: Convert/reconvert to utf8. By Questor
        iconv -f "$CHARSET" -t utf8 "$LINE_FILE" -o "$LINE_FILE" 2> STDERR_OP 1> STDOUT_OP

        STDERR_OP=$(cat STDERR_OP)
        rm -f STDERR_OP
    fi

    # NOTE: Remove "BOM" if exists as it is unnecessary. By Questor
    # [Refs.: https://stackoverflow.com/a/2223926/3223785 ,
    # https://stackoverflow.com/a/45240995/3223785 ]
    sed -i '1s/^\xEF\xBB\xBF//' "$LINE_FILE"

    if [ -n "$STDERR_OP" ] ; then
        echo "ERROR: \"$STDERR_OP\""
    fi
    STDOUT_OP=$(cat STDOUT_OP)
    rm -f STDOUT_OP
    if [ -n "$STDOUT_OP" ] ; then
        echo "RESULT: \"$STDOUT_OP\""
    fi
done
# [Refs.: https://justrocketscience.com/post/handle-encodings , 
# https://stackoverflow.com/a/9612232/3223785 , 
# https://stackoverflow.com/a/13659891/3223785 ]

Гибридное решение с перекодированием и vim ...

#!/bin/bash

find <YOUR_FOLDER_PATH> -name '*' -type f -exec grep -Iq . {} \; -print0 | 
while IFS= read -r -d $'\0' LINE_FILE; do
    CHARSET=$(uchardet $LINE_FILE)
    REENCSED=`echo $CHARSET | sed 's#^x-mac-#mac#'`
    echo "\"$CHARSET\" \"$LINE_FILE\""

    # NOTE: Convert/reconvert to utf8. By Questor
    recode $REENCSED..UTF-8 "$LINE_FILE" 2> STDERR_OP 1> STDOUT_OP

    STDERR_OP=$(cat STDERR_OP)
    rm -f STDERR_OP
    if [ -n "$STDERR_OP" ] ; then

        # NOTE: Convert/reconvert to utf8. By Questor
        bash -c "</dev/tty vim -u NONE +\"set binary | set noeol | set nobomb | set encoding=utf-8 | set fileencoding=utf-8 | wq\" \"$LINE_FILE\""

    else

        # NOTE: Remove "BOM" if exists as it is unnecessary. By Questor
        # [Refs.: https://stackoverflow.com/a/2223926/3223785 ,
        # https://stackoverflow.com/a/45240995/3223785 ]
        sed -i '1s/^\xEF\xBB\xBF//' "$LINE_FILE"

    fi
done

ПРИМЕЧАНИЕ: Это было решение с наибольшим количеством совершенных конверсий. Кроме того, у нас не было усеченных файлов.


ВНИМАНИЕ: Сделайте резервную копию ваших файлов и используйте инструмент слияния для проверки / сравнения изменений. Проблемы вероятно появятся!

СОВЕТ: Команда sed -i '1s/^\xEF\xBB\xBF//' "$LINE_FILE" может быть выполнена после предварительного сравнения с инструментом слияния после преобразования без него, поскольку это может вызвать «различия».

ПРИМЕЧАНИЕ: При поиске с использованием команды «find» отображаются все недвоичные файлы из «YOUR_FOLDER_PATH» и его подпапок.

Спасибо!

0 голосов
/ 07 октября 2015
Команда

enca не работает для моего текстового файла на упрощенном китайском языке с кодировкой GB2312.

Вместо этого я использую следующую функцию для преобразования текстового файла для меня. Конечно, вы можете перенаправить вывод в файл.

Требуется chardet и iconv .

detection_cat () 
{
    DET_OUT=$(chardet $1);
    ENC=$(echo $DET_OUT | sed "s|^.*: \(.*\) (confid.*$|\1|");
    iconv -f $ENC $1
}
0 голосов
/ 03 апреля 2014

Проверьте инструменты, доступные для преобразования данных в linux cli: https://www.debian.org/doc/manuals/debian-reference/ch11.en.html

Кроме того, есть квест, чтобы узнать полный список кодировок, доступных в iconv. Просто запустите iconv --list и выясните, что имена кодировок отличаются от имен, возвращаемых инструментом uchardet (например: x-mac-кириллица в uchardet и mac-кириллица в iconv)

...