为什么将 sed 输出重定向到相同的输入文件会导致我的机器无响应?

为什么将 sed 输出重定向到相同的输入文件会导致我的机器无响应?

我试图sed替换一个大文件 (100 MB) 中的一些关键字。我不知道-i(inplace) 选项,所以我的第一次尝试是像这样重定向:

sed 's/original/edited/g' file.log >> file.log

之后发生的事情是我的 PC 停止了,几乎没有键盘输入。我尝试了不同的控制台++ Ctrl,但在慢慢输入用户名后,它也停止了。没有键盘,我唯一的选择就是硬件重置机器。登录后,我看到 file.log 大约有 8 GB。AltF1

我真的很想了解为什么执行该命令会导致系统如此无响应,以及系统级别是否存在触发警报并终止有问题的进程的机制?

答案1

您的sed命令试图读取它正在附加到的文件。它永远不会到达文件末尾,但会耗费大量的 CPU 时间。这就是发明 ^C(中断当前进程)的原因。

答案2

在任何情况下,将内容追加到您读取的文件都不是一个好主意,因为最终文件会越来越大。如果您确实想将内容写回到文件中,则应使用以下标志-i

sed -i 's/original/edited/g' file.log

或者如果您希望它在进行更改之前创建备份,您可以向标志添加文件后缀-i

sed -i.bak 's/original/edited/g' file.log

这将创建一个名为的文件file.log.bak,然后进行更改,您尝试将内容附加到您正在读取的文件中,我们在程序员的俚语中称之为数据竞争,其中不同的进程争夺同一数据源,无论是输入还是输出。这也是您的机器停止运行的原因。

答案3

正如前面所说,>>附加到文件,因此您的sed命令将坐在那里读取它刚刚输出的行,然后再输出更多行。如果您想就地替换文件,>仍然行不通,但您知道 的sed选项-i,这绝对是您想要的。

但是,如果您非常确定想要将其附加到以流形式读取的文件中,并且只想执行一次传递,请考虑使用包sponge中的功能moreutils

sed 's/original/edited/g' file.log | sponge >> file.log

sponge从 stdin 读取到内存直到 EOF,然后将其所有内容转储到 stdout,因此sed将到达文件末尾,停止读取,关闭它,然后 sponge 将开始向其中附加内容。

相关内容