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

med*_*iev 79 shell io-redirection text-processing

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

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

for file in *.php
do
    iconv -f cp1251 -t utf8 "$file"
done
Run Code Online (Sandbox Code Playgroud)

Gil*_*il' 83

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

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

for file in *.php
do
    iconv -f cp1251 -t utf8 -o "$file.new" "$file" &&
    mv -f "$file.new" "$file"
done
Run Code Online (Sandbox Code Playgroud)

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

for file in *.php
do
    iconv -f cp1251 -t utf8 "$file" >"$file.new" &&
    mv -f "$file.new" "$file"
done
Run Code Online (Sandbox Code Playgroud)

Colin Watson 的sponge实用程序(包含在Joey Hess 的 moreutils 中)自动执行此操作:

for file in *.php
do
    iconv -f cp1251 -t utf8 "$file" | sponge "$file"
done
Run Code Online (Sandbox Code Playgroud)

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

  • GNU sed 和 Perl-p可以-i选择替换文件。
  • 如果您的文件非常大,您的过滤器只修改或删除某些部分,但从来没有增加的东西(例如greptrsed 's/long input text/shorter text/'),你就像生活危险的是,你可能要真正修改文件的地方(其他的解决方案在这里提到的创建新的输出文件并将其移动到最后,因此如果命令因任何原因中断,原始数据不会改变)。

  • 我不太确定“海绵”的作者是否应该完全归功于乔伊·赫斯(Joey Hess);他维护的是包含 `sponge` 的包 `moreutils`,但关于 `sponge` 的起源,通过访问 `moreutils` 主页上的链接,我发现它最初是 [已发布并建议包含在内] (http://riva.ucam.org/~cjwatson/blog/2006/02/06#2006-02-06-sponge) 由 Colin Watson 撰写:“乔伊写道,缺乏符合 Unix 哲学的新工具。我写过的这类东西中我最喜欢的是“海绵””(2006 年 2 月 6 日星期一)。 (3认同)
  • 我使用 Mac OS,iconv 中没有 -o 选项,我必须将 ` iconv -f cp1251 -t utf8 -o "$file.new" "$file"` 更改为 `iconv -f cp1251 -t utf8 "$文件”>“$file.new”` (3认同)

man*_*ork 66

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

for file in *.php
do
    recode cp1251..utf8 "$file"
done
Run Code Online (Sandbox Code Playgroud)

由于recode接受多个输入文件作为参数,您可以避免for循环:

recode cp1251..utf8 *.php
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,这值得更多赞成。只是想知道手册中关于编码之间的 2 个点的位置... (2认同)
  • “REQUEST 通常看起来像 BEFORE..AFTER,BEFORE 和 AFTER 是字符集。” 该手册确实很难遵循所有那些双点(这是语法的一部分)和三点(这意味着更多)。一个建议:试试“信息重新编码”。比较啰嗦。 (2认同)