我在 Gnu/Linux 服务器上启动一个应用程序我的应用程序:
./myApp &>myApp.log &
当然,日志文件很快就会变得非常大。
我想使用sed减少它(我知道日志旋转但我的申请仍是草稿)。
但如果我使用这样的命令
sed -i "1,200d" myApp.lo
文件确实被截断了,但此后,应用程序不会再向文件中写入任何数据。
为什么?
答案1
当一个文件被打开时,系统会为其分配一个文件描述符。当文件打开时,可以通过这个FD来访问它。
当你运行 sed 命令时,它会通过将文件复制到新文件来截断文件。你可以看到这一点,因为 inode 编号发生了变化
ls -i log
131122 log
sed -i "1,200d" log
ls -i log
131090 log
实际情况是,文件正在被写入,您通过将内容复制到另一个文件来截断它,但是原始文件被 myApp 保持打开状态,并且仍在被 myApp 写入,只是在 myApp 完成时将其标记为准备删除。您可以使用 lsof 查看此情况。
lsof | grep myapp.log
myapp 11334 iain 1w REG 253,2 54 131122 /home/iain/myapp.log
sed -i "1,200d" myapp.log
lsof | grep myapp.log
myapp 11334 iain 1w REG 253,2 416 131122 /home/iain/myapp.log (deleted)
如果可以的话,您应该修改您的应用程序,以便它可以接受一个信号,告诉它关闭然后重新打开日志文件,这将允许它与 logrotate 之类的程序很好地配合使用。
如果你无法修改你的应用程序来处理信号,那么你可以使用 fifo。我在这里解释了如何做到这一点前一段时间。
答案2
您的sed
命令将创建一个新文件并将处理后的输出写入该文件。然后它将重命名新文件以替换旧文件。
该进程仍将写入您最初将输出重定向到的同一文件。该文件现已被删除,但这并不妨碍已打开该文件的进程写入该文件。
您应该开始准备使用logrotate
。它不会解决所有问题,但它可以解决的一个问题是保留多个日志文件。进程在文件旋转后继续写入文件一段时间并不是什么大问题。
但是,完整的解决方案需要您进行一些编码。您的应用程序需要定期或在指示旋转时打开日志文件进行写入。这意味着应用程序还需要知道日志文件的文件名。
答案3
当您运行./myApp &>myApp.log
命令时,输出将重定向到文件名为 myApp.log 的新文件。
当您运行sed -i "1,200d" myApp.log
命令时,将创建一个名为 myApp.log 的新文件。
这里的问题是,原始命令仍在写入最初创建的文件,但该文件已被取消链接,并且在文件系统中不再有名称。但是,该文件仍然存在,因为它仍处于打开状态。
这样做的结果是,在运行 sed 命令后您不仅不再看到输出,而且如果您的目标是释放空间,那么在关闭原始文件之前也不会发生这种情况。