39

我在我的 OSX 上有一个 PHP 项目,它是 latin1 编码的。现在我需要将文件转换为 UTF8。我不是一个 shell 编码器,我尝试了一些从互联网上找到的东西:

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

但这不会创建目录结构,并且在运行时会给我带来大量错误。任何人都可以提出巧妙的解决方案吗?

4

12 回答 12

45

你不应该那样使用lsfor循环也不合适。此外,目标目录应该在源目录之外。

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/"{}"' \;
于 2010-12-28T09:00:37.163 回答
22

这将转换所有具有.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 似乎在读取输入文件之前创建了输出文件,这意味着如果输入和输出文件具有相同的名称,则输入文件在读取之前会被一个空文件覆盖。

于 2014-07-19T02:33:58.497 回答
21

一些很好的答案,但我发现这在我的情况下要容易得多,因为有数百个文件的嵌套目录要转换:

警告:这会将文件写入到位,因此请备份

$ vim $(find . -type f)

# in vim, go into command mode (:)
:set nomore
:bufdo set fileencoding=utf8 | w
于 2016-02-11T02:14:06.547 回答
12

要将完整的目录树从 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. 在 macOS 上测试。

顺便说一句:检查您的文件编码:

file -I file.php

获取编码信息。

希望这可以帮助。

于 2015-06-27T09:05:15.127 回答
6

我创建了以下脚本,(i)备份目录“converted”中的所有 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
于 2015-11-30T22:25:21.977 回答
6

在 unix.stackexchange.com 上问了一个类似的问题,用户 manatwork 建议重新编码,这非常好。

我一直在使用它来将 ucs-2 转换为 utf-8

recode ucs-2..utf-8 *.txt
于 2017-08-23T22:51:41.493 回答
5

如果您必须转换的所有文件都是 .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:

于 2010-12-28T08:45:18.260 回答
3

On Windows Git Bash, I got these errors with several of the proposed solutions:

  • find: Only one instance of {} is supported with -exec ... +
  • find: In ‘-exec ... {} +’ the ‘{}’ must appear by itself, but you specified ‘source={};...’</li>

But that (a mix of other proposed solutions) worked:

for fileToConvert in $(find . -type f -name \*.js); do iconv -f iso-8859-1 -t utf-8 <"$fileToConvert" >~/temp-iconv.txt ; mv -f ~/temp-iconv.txt "$fileToConvert" ; done
于 2020-05-08T15:40:21.927 回答
1

Use mkdir -p "${a%/*}"; before iconv.

Note that you are using a potentially dangerous for construct when there are spaces in filenames, see http://porkmail.org/era/unix/award.html.

于 2010-12-28T08:53:30.790 回答
1

上面的答案一切都很好,但如果这是一个“混合”项目,即已经有 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 {} \;
于 2016-04-04T10:46:54.030 回答
0

使用 Dennis Williamson 和 Alberto Zaccagni 的答案,我想出了以下脚本,它可以转换所有子目录中指定文件类型的所有文件。然后将输出收集到一个文件夹中,该文件夹由/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

函数 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

玩得开心,如果有任何意见可以改进它,我将不胜感激,谢谢!

于 2015-04-15T08:32:39.853 回答
0
find . -iname "*.php" | xargs -I {} echo "iconv -f ISO-8859-1 -t UTF-8 \"{}\" > \"{}-utf8.php\""
于 2014-06-25T18:53:20.003 回答