我试图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 将开始向其中附加内容。