Пакетное преобразование файлов latin-1 в utf-8 с помощью iconv - PullRequest
29 голосов
/ 28 декабря 2010

У меня есть один проект PHP на моем OSX, который находится в кодировке latin1. Теперь мне нужно конвертировать файлы в UTF8. Я не много шелл-кодер, и я попробовал кое-что, что я нашел из интернета:

mkdir new  
for a in `ls -R *`; do iconv -f iso-8859-1 -t utf-8 <"$a" >new/"$a" ; done

Но это не создает структуру каталогов и дает мне кучу ошибок при запуске. Кто-нибудь может придумать аккуратное решение?

Ответы [ 11 ]

40 голосов
/ 28 декабря 2010

Вы не должны использовать ls подобным образом, и цикл for также не подходит. Кроме того, каталог назначения должен быть вне исходного каталога.

mkdir /path/to/destination
find . -type f -exec iconv -f iso-8859-1 -t utf-8 "{}" -o /path/to/destination/"{}" \;

Нет необходимости в петле. Опция -type f включает файлы и исключает каталоги.

Edit:

Версия iconv для OS X не имеет опции -o. Попробуйте это:

find . -type f -exec bash -c 'iconv -f iso-8859-1 -t utf-8 "{}" > /path/to/destination/"{}"' \;
14 голосов
/ 11 февраля 2016

Несколько хороших ответов, но я обнаружил, что это намного проще в моем случае с вложенным каталогом из сотен файлов для преобразования:

ПРЕДУПРЕЖДЕНИЕ: это позволит записать файлы на место, поэтому сделайте резервную копию

$ vim $(find . -type f)

# in vim, go into command mode (:)
:set nomore
:bufdo set fileencoding=utf8 | w
11 голосов
/ 19 июля 2014

Конвертирует все файлы с расширением .php в текущем каталоге и его подкаталогах, сохраняя структуру каталога:

    find . -name "*.php" -exec sh -c "iconv -f ISO-8859-1 -t UTF-8 {} > {}.utf8"  \; -exec mv "{}".utf8 "{}" \;

Примечания:

Чтобы получить списокДля файлов, которые будут предварительно нацелены, просто запустите команду без флагов -exec (например: find . -name "*.php").Создание резервной копии - хорошая идея.

Использование sh, подобного этому, позволяет передавать и перенаправлять с помощью -exec, что необходимо, поскольку не все версии iconv поддерживают флаг -o.

Добавление .utf8 к имени файла вывода и последующее удаление может показаться странным, но это необходимо.Использование одного и того же имени для выходных и входных файлов может вызвать следующие проблемы:

  • Для больших файлов (по моему опыту около 30 КБ) это вызывает дамп памяти (или termination by signal 7)

  • Некоторые версии iconv создают выходной файл до того, как прочитают входной файл, что означает, что если входные и выходные файлы имеют одинаковые имена, входной файл перезаписывается пустымфайл перед прочтением.

8 голосов
/ 27 июня 2015

Для рекурсивного преобразования полного дерева каталогов из iso-8859-1 в utf-8, включая создание подкаталогов, ни одно из приведенных выше кратких решений не сработало, поскольку структура каталога не была создана в целевом объекте. На основании ответа Денниса Уильямсона я нашел следующее решение:

find . -type f -exec bash -c 't="/tmp/dest"; mkdir -p "$t/`dirname {}`"; iconv -f iso-8859-1 -t utf-8 "{}" > "$t/{}"' \;

Это создаст клон текущего поддерева каталога в /tmp/dest (с учетом ваших потребностей), включая все подкаталоги и со всеми iso-8859-1 файлами, преобразованными в utf-8. Проверено на macosx.

Кстати: проверьте кодировки файлов с помощью:

file -I file.php

для получения информации о кодировке.

Надеюсь, это поможет.

5 голосов
/ 01 декабря 2015

Я создаю следующий сценарий, который (i) создает резервные копии всех текстовых файлов в каталоге, «преобразованных», (ii) проверяет кодировку каждого текстового файла и (iii) преобразует в UTF-8 только текстовые файлы в ISOКодировка 8859-1.

FILES=*.tex
for f in $FILES
do
  filename="${f%.*}"
  echo -n "$f"
#file -I $f
  if file -I $f | grep -wq "iso-8859-1"
  then
    mkdir -p converted
    cp $f ./converted
    iconv -f ISO-8859-1 -t UTF-8 $f > "${filename}_utf8.tex"
    mv "${filename}_utf8.tex" $f
    echo ": CONVERTED TO UTF-8."
  else
    echo ": UTF-8 ALREADY."
  fi
done
5 голосов
/ 28 декабря 2010

Если все файлы, которые вы должны преобразовать, - это .php, вы можете использовать следующее, которое по умолчанию является рекурсивным:

for a in $(find . -name "*.php"); do iconv -f iso-8859-1 -t utf-8 <"$a" >new/"$a" ; done

Я полагаю, что ваши ошибки были связаны с тем, что ls -R также производитвывод, который не может быть распознан iconv как допустимое имя файла, что-то вроде ./my/dir/structure:

4 голосов
/ 24 августа 2017

На unix.stackexchange.com был задан похожий вопрос, и пользователь manatwork предложил перекодировать, что очень хорошо помогает.

Я использовал его для преобразования ucs-2 в utf-8 на месте

recode ucs-2..utf-8 *.txt
1 голос
/ 04 апреля 2016

С этими ответами все в порядке, но если это «смешанный» проект, то есть уже есть файлы UTF8, то у нас могут возникнуть проблемы, поэтому вот мое решение, я сначала проверяю кодировку файлов.

#!/bin/bash
# file name: to_utf8

# current encoding:
encoding=$(file -i "$1" | sed "s/.*charset=\(.*\)$/\1/")

if [  "${encoding}" = "iso-8859-1" ] || [ "${encoding}" = "iso-8859-2" ]; 
then
echo "recoding from ${encoding} to UTF-8 file : $1"
recode ISO-8859-2..UTF-8 "$1"
fi

#example:
#find . -name "*.php" -exec to_utf8 {} \;
1 голос
/ 28 декабря 2010

Используйте mkdir -p "${a%/*}"; перед iconv.

Обратите внимание, что вы используете потенциально опасную конструкцию for, когда в именах файлов есть пробелы, см. http://porkmail.org/era/unix/award.html.

0 голосов
/ 15 апреля 2015

Используя ответы Денниса Уильямсона и Альберто Закканьи, я придумал следующий скрипт, который преобразует все файлы указанного типа из всех подкаталогов.Затем выходные данные собираются в одну папку, которая задается как /path/to/destination

mkdir /path/to/destination
for a in $(find . -name "*.php"); 
do 
        filename=$(basename $a);
        echo $filename
        iconv -f iso-8859-1 -t utf-8 <"$a" >"/path/to/destination/$filename"; 
done

Базовое имя функции возвращает имя файла без пути к файлу.

Альтернатива (пользователь интерактивно): Теперь я также создал пользовательский интерактивный скрипт, который позволяет вам решить, хотите ли вы перезаписать старые файлы или просто переименовать их.Дополнительная благодарность: tbsalling

for a in $(find . -name "*.tex");
do
        iconv -f iso-8859-1 -t utf-8 <"$a" >"$a".utf8 ;
done
echo "Should the original files be replaced (Y/N)?"
read replace
if [ "$replace" == "Y" ]; then
    echo "Original files have been replaced."
    for a in $(find . -name "*.tex.utf8");
        do
            file_no_suffix=$(basename -s .tex.utf8 "$a");
            directory=$(dirname "$a");
            mv "$a" "$directory"/"$file_no_suffix".tex;
        done
else
        echo "Original files have been converted and converted files were saved with suffix '.utf8'"
fi

Удачи с этим, и я был бы благодарен за любые комментарии, чтобы улучшить его, спасибо!

...