为什么将文件输出重定向至其自身会产生一个空白文件?

为什么将文件输出重定向至其自身会产生一个空白文件?

为什么将文件输出重定向至其自身会产生一个空白文件?

在 Bash 中,为什么

less foo.txt > foo.txt

fold foo.txt > foo.txt

生成一个空的foo.txt? 由于诸如 之类的附加操作less eggs.py >> eggs.py会生成 中的两个文本副本eggs.py,因此人们可能认为覆盖操作会生成一个文本副本。

请注意,我并不是说这是一个错误,它更有可能指向 Unix 的某些深层问题。

答案1

当您使用时>,文件将以截断模式打开,因此在命令尝试读取文件之前其内容会被删除。

当您使用 时>>,文件将以追加模式打开,因此现有数据将被保留。但是,在这种情况下,使用同一个文件作为输入和输出仍然非常危险。如果文件足够大而无法容纳读取输入缓冲区大小,则其大小可能会无限增长,直到文件系统已满(或达到磁盘配额)。

如果您想要使用不支持就地修改的命令将文件同时用作输入和输出,则可以使用以下几种解决方法:

  • 使用中间文件,完成后覆盖原始文件,并且仅在运行实用程序时没有发生错误时才覆盖原始文件(这是最安全和最常见的方法)。

    fold foo.txt > fold.txt.$$ && mv fold.txt.$$ foo.txt
    
  • 避免使用中间文件,因为如果发生错误或中断,可能会造成部分或全部数据丢失。在此示例中,的内容foo.txt作为输入传递给子壳(括号内)文件被删除。由于子 shell 在读取数据时保持打开状态,因此前一个 inode 仍处于活动状态。内部实用程序(此处fold)写入的文件虽然具有相同的名称(foo.txt),但指向不同的 inode,因为旧目录条目已被删除,因此从技术上讲,在此过程中有两个具有相同名称的不同“文件”。当子 shell 结束时,旧 inode 被释放,其数据丢失。请注意确保您有足够的空间同时临时存储旧文件和新文件,否则您将丢失数据。

    (rm foo.txt; fold > foo.txt) < foo.txt
    

答案2

在应用程序有机会读取文件之前,shell 会打开文件进行写入。打开文件进行写入会截断它。

答案3

在 bash 中,流重定向运算... > foo.txt符清空foo.txt 在评估左操作数之前

可以使用命令替换并打印其结果作为解决方法。此解决方案所需的额外字符比其他答案少:

printf '%s\n' "$(less foo.txt)" > foo.txt

注意:此命令不会保留 中的任何尾随换行符foo.txt。请参阅下面的评论部分以获取更多信息

在这里,命令替换$(...)被评估流重定向操作符>,从而保存信息。

相关内容