web-dev-qa-db-ja.com

iconvを使用してlatin-1ファイルをutf-8にバッチ変換する

私はこれをPHP latin1 -encodingにある私のOSXのプロジェクトに持っています。今ではファイルをUTF8に変換する必要があります。インターネットから:

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

しかし、それではディレクトリ構造が作成されず、実行時に大量のエラーが発生します。誰でもきちんとした解決策を思い付くことができますか?

31
Jasmo

そのようなlsを使用すべきではなく、forループも適切ではありません。また、宛先ディレクトリはソースディレクトリの外部にある必要があります。

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

ループの必要はありません。 -type fオプションにはファイルが含まれ、ディレクトリは除外されます。

編集:

OS Xバージョンのiconvには-oオプションがありません。これを試して:

find . -type f -exec bash -c 'iconv -f iso-8859-1 -t utf-8 "{}" > /path/to/destination/"{}"' \;
41

いくつかの良い答えがありますが、私の場合は、変換する何百ものファイルのネストされたディレクトリを使用する方がはるかに簡単です。

警告:これはファイルを所定の場所に書き込むため、バックアップを作成します

$ vim $(find . -type f)

# in vim, go into command mode (:)
:set nomore
:bufdo set fileencoding=utf8 | w
15
cmcginty

これにより、現在のディレクトリとそのサブディレクトリにある、.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 KB)の場合、コアダンプ(またはtermination by signal 7)が発生します

  • Iconvの一部のバージョンは、入力ファイルを読み取る前に出力ファイルを作成するようです。つまり、入力ファイルと出力ファイルが同じ名前の場合、入力ファイルは読み取られる前に空のファイルで上書きされます。

11
UTF_or_Death

サブディレクトリの作成を含む完全なディレクトリツリーを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でテスト済み。

Btw:ファイルエンコードを次の方法で確認します。

file -I file.php

エンコード情報を取得します。

お役に立てれば。

8

変換する必要があるすべてのファイルが.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:のようなもの)を生成するという事実によるものだと思います

5

次のスクリプトを作成します。(i)「変換済み」ディレクトリ内のすべてのtexファイルをバックアップし、(ii)すべてのtexファイルのエンコーディングをチェックし、(iii)ISO-8859-1のtexファイルのみをUTF-8に変換しますエンコーディング。

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
Ricardo Terra

Unix.stackexchange.comでも同様の質問が出され、ユーザーmanatworkが再コーディングを提案しました。

私はそれを使用してucs-2をutf-8に変換しました

recode ucs-2..utf-8 *.txt
4
Scott

使用する mkdir -p "${a%/*}"; iconvの前。

ファイル名にスペースが含まれる場合、潜在的に危険なforコンストラクトを使用していることに注意してください。 http://porkmail.org/era/unix/award.html を参照してください。

1
user502515

上記の答えはすべて問題ありませんが、これが「混合」プロジェクトである場合、つまり既に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
konrad_firm

Dennis WilliamsonとAlberto Zaccagniの回答を使用して、指定したファイルタイプのすべてのファイルをすべてのサブディレクトリから変換する次のスクリプトを思い付きました。出力は、/path/to/destinationで指定された1つのフォルダーに収集されます

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

関数basenameは、ファイルのパスなしでファイル名を返します。

代替(ユーザーインタラクティブ):ここで、古いファイルを上書きするか、単に名前を変更するかを決定できるユーザーインタラクティブスクリプトも作成しました。追加の感謝は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

これを楽しんでください、それを改善するためのコメントに感謝します、ありがとう!

0
tc88
find . -iname "*.php" | xargs -I {} echo "iconv -f ISO-8859-1 -t UTF-8 \"{}\" > \"{}-utf8.php\""
0
calebern