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

ces*_*hon 13 command-line sed

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

sed 's/original/edited/g' file.log >> file.log
Run Code Online (Sandbox Code Playgroud)

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

我真的很想了解为什么该命令的执行能够使系统如此无响应,以及系统级别是否存在触发警报并终止违规进程的机制?

wal*_*tor 18

您的sed命令试图读取它附加到的文件。它永远不会到达文件结尾,但会尝试消耗大量 CPU 时间。这就是 ^C(中断电流过程)被发明的原因。


Vid*_*uth 18

附加回您读取的文件在任何情况下都不是一个好主意,因为您最终会得到一个不断增长的文件。如果你真的想写回文件,你应该使用这个-i标志:

sed -i 's/original/edited/g' file.log
Run Code Online (Sandbox Code Playgroud)

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

sed -i.bak 's/original/edited/g' file.log
Run Code Online (Sandbox Code Playgroud)

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

  • 我很惊讶这是被接受的答案,因为它甚至没有解决OP的问题“我真的很想了解为什么该命令的执行能够使系统如此反应迟钝,以及系统级别是否存在机制触发警报并杀死有问题的进程?”` (2认同)

ymb*_*rtt 10

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

但是,如果您绝对确定要将作为流读取的文件附加到您正在读取的文件中,并且只想执行一次此操作,请考虑spongemoreutils包中使用;

sed 's/original/edited/g' file.log | sponge >> file.log
Run Code Online (Sandbox Code Playgroud)

sponge从标准输入读取到内存直到 EOF,然后将其所有内容转储到标准输出,因此sed将到达文件末尾,停止读取它,关闭它,然后海绵将开始附加到它。

  • `sponge` 是一个很好的实用工具,但是 `sed` 已经有一个 `-i` 选项:`-i[SUFFIX],--in-place[=SUFFIX],就地编辑文件(如果 SUFFIX,则进行备份提供)`。 (2认同)