如何使 iconv 用转换后的输出替换输入文件?

如何使 iconv 用转换后的输出替换输入文件?

我有一个 bash 脚本,它枚举目录中的每个 *.php 文件并应用于iconv它。这会在 STDOUT 中获得输出。

由于添加-o参数(根据我的经验)实际上可能在转换发生之前写入一个空白文件,因此我如何调整我的脚本以进行转换,然后覆盖输入文件?

for file in *.php
do
    iconv -f cp1251 -t utf8 "$file"
done

答案1

这是行不通的,因为iconv首先创建输出文件(因为该文件已经存在,所以它会截断它),然后开始读取其输入文件(现在为空)。大多数程序都是这样运行的。

为输出创建一个新的临时文件,然后将其移动到位。

for file in *.php
do
    iconv -f cp1251 -t utf8 -o "$file.new" "$file" &&
    mv -f "$file.new" "$file"
done

如果您的平台iconv没有-o,您可以使用 shell 重定向来达到相同的效果。

for file in *.php
do
    iconv -f cp1251 -t utf8 "$file" >"$file.new" &&
    mv -f "$file.new" "$file"
done

科林·沃森的sponge效用(包括在Joey Hess 的 moreutils)自动执行此操作:

for file in *.php
do
    iconv -f cp1251 -t utf8 "$file" | sponge "$file"
done

这个答案不仅适用于iconv任何过滤程序。一些特殊情况值得一提:

  • GNU sed 和 Perl-p可以-i选择就地替换文件。
  • 如果你的文件非常大,你的过滤器只是修改或删除一些部分,但从不添加东西(例如,,,grep),并且你喜欢危险的生活,你可能想真正地trsed 's/long input text/shorter text/'就地修改文件(此处提到的其他解决方案创建一个新的输出文件并将其移至最后的位置,因此如果命令因任何原因中断,原始数据不会更改)。

答案2

另一种方法是recode,它使用 libiconv 库进行某些转换。它的行为是用输出替换输入文件,所以这将起作用:

for file in *.php
do
    recode cp1251..utf8 "$file"
done

由于recode接受多个输入文件作为参数,因此您可以节省for循环:

recode cp1251..utf8 *.php

答案3

目前

find . -name '*.php' -exec iconv -f CP1251 -t UTF-8 {} -o {} \;

奇迹般有效

答案4

这里有一个简单的例子。它应该为您提供足够的信息来开始。

#!/bin/bash
#conversor.sh
#Author.....: dede.exe
#E-mail.....: [email protected]
#Description: Convert all files to a another format
#             It's not a safe way to do it...
#             Just a desperate script to save my life...
#             Use it such a last resort...

to_format="utf8"
file_pattern="*.java"

files=`find . -name "${file_pattern}"`

echo "==================== CONVERTING ===================="

#Try convert all files in the structure
for file_name in ${files}
do
        #Get file format
        file_format=`file $file_name --mime-encoding | cut -d":" -f2 | sed -e 's/ //g'`

        if [ $file_format != $to_format ]; then

                file_tmp="${unit_file}.tmp"

                #Rename the file to a temporary file
                mv $file_name $file_tmp

                #Create a new file with a new format.
                iconv -f $file_format -t $to_format $file_tmp > $file_name

                #Remove the temporary file
                rm $file_tmp

                echo "File Name...: $file_name"
                echo "From Format.: $file_format"
                echo "To Format...: $to_format"
                echo "---------------------------------------------------"

        fi
done;

相关内容