如果磁盘空间不足,如何从shell脚本重写文件而不会有截断文件的危险?

时间:2013-04-22 09:54:10

标签: perl shell diskspace

如果磁盘空间不足,如何从shell脚本重写文件而不会有截断文件的危险?

这个方便的perl one liner在名为test.txt的文件中用“bar”替换所有出现的“foo”:

perl -pi -e 's/foo/bar/g' test.txt

这非常有用,但是......

如果test.txt所在的文件系统磁盘空间不足,test.txt将被截断为零字节文件。

是否有一种简单的,无竞争条件的方法来避免这种截断?

我希望test.txt文件保持不变,如果文件系统空间不足,则返回错误的命令。

理想情况下,应该可以从shell脚本中轻松使用该解决方案,而无需安装其他软件(超出“标准”UNIX工具,如sed和perl)。

谢谢!

2 个答案:

答案 0 :(得分:4)

一般来说,这是不可能做到的。请记住,空间不足情况可能会触发给出就地编辑的外观的操作序列中的任何位置。一旦文件系统已满,perl可能无法撤消先前的操作以恢复原始状态。

使用-i开关的更安全的方法是使用非空的备份后缀,例如

perl -pi.bak -e 's/foo/bar/g' test.txt

这样,如果在此过程中出现问题,您仍然可以获得原始数据。

如果您想自己动手,请务必检查close系统调用返回的值。正如Linux手册页所述,

  

不检查close()的返回值是一个常见但严重的编程错误。很可能首先在最终close()报告先前 write(2)操作的错误。关闭文件时不检查返回值可能会导致数据无声丢失。使用NFS和磁盘配额尤其可以观察到这种情况。

与生活中的其他事物一样,给自己留下更多的错误余地。磁盘很便宜。从沙发垫上挖出口袋,然后自己买半个太字节。

答案 1 :(得分:3)

来自perldoc perlrun

  

-i[extension]

     

指定由“<>”构造处理的文件将进行就地编辑。   它通过重命名输入文件,通过原始打开输出文件来完成此操作   name,并选择该输出文件作为print()语句的默认值。该   扩展(如果提供)用于修改旧文件的名称以进行创建   备份副本,遵循以下规则:

     

如果未提供扩展,则不进行备份,当前文件为   覆盖。

     

[...]

改写:

  1. 备份文件名是根据-i - 开关的值确定的,如果有的话。
  2. 原始文件重命名为新文件名,并为脚本打开。在大多数文件系统上重命名都是原子的。
  3. 打开具有原始文件名称的文件以进行写入。该文件将以长度为零开始,但与原始文件(现在具有不同的名称)不同。
  4. 脚本完成后,如果未提供明确的备份扩展名,则删除备份文件。然后原始文件丢失。
  5. 如果系统用完了驱动器空间,那么新文件就会受到威胁,而不是永远不会复制或移动的原始文件(至少在具有类似inode概念的文件系统上)。