为什么将文件输出重定向到其自身会生成空白文件?


19

为什么将文件输出重定向到其自身会生成空白文件?

在Bash中陈述,为什么

less foo.txt > foo.txt

fold foo.txt > foo.txt

产生一个空的foo.txt?由于诸如这样的追加会在中less eggs.py >> eggs.py生成文本的两个副本,因此eggs.py可以期望覆盖会生成文本的一个副本。

注意,我并不是说这是一个错误,它更可能是指向Unix某些深层内容的指针。


Answers:


20

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

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

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

  • 仅在运行实用程序时未发生错误的情况下,使用中间文件并覆盖原始文件(这是最安全,更常见的方法)。

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

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

3
sponge来自moreutils的帮助也可以。fold foo.txt | sponge foo.txt–或者fold foo.txt | sponge !$也应该这样做。
slhck

@slhck确实,海绵也可以完成这项工作。但是,既没有由POSIX指定,也没有像OS这样在Unix中成为主流,所以它不太可能出现。
jlliagre

它不是像它不能目前虽然;)
slhck


0

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

一个人可能使用命令替换并将其结果打印为一种解决方法。与其他答案相比,此解决方案所需的其他字符更少:

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

注意:此命令不会保留中的任何尾随换行符foo.txt。在下面的评论部分中查看更多信息

在此,子外壳$(...)程序流重定向操作符之前进行评估>,因此可以保留信息。


@KamilMaciorowski:其实有tmp=$(cmd; printf q);  printf '%s' "${tmp%q}"。但是您错过了这个答案的另一个问题:当它表示“命令替换”时,它会显示“ subshel​​l”。是的,命令替换通常是子外壳程序,反之亦然,子外壳程序通常对于此问题没有帮助。
斯科特

@KamilMaciorowski我为错过所有这些感到很难过。感谢您指出所有这些。对于您的第(4)点:反引号是否有用,即保留尾随的换行符?
路易·雅各布·勒贝尔

@Scott感谢您的回复。我将“子外壳”更改为“命令替换”。顺便说一句,我想知道两者之间的确切区别是什么。
Louis-Jacob Lebel

不,反引号(反引号)也会删除尾随换行符。
卡米尔Maciorowski

好吧,我现在添加了一条警告消息。如果找到解决方案,我将其删除。
Louis-Jacob Lebel
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.