我对Linux上的shell编程还有一些新的东西,在我的Linux实例中,我将程序的stdout和stderr以下列方式redirect到两个文件,并在后台运行
myprog > run.log 2>> err.log &
这工作得很好,我得到了我想要的行为
现在有另一个后台进程监视run.log和err.log,如果日志文件增长超过一定的阈值,则将其移动到其他文件名。
例如mv err.log err[date-time].log
我的期望是,在这个文件移动发生之后,err.log将被myprog输出redirect重新创build,并且新的输出将被写入到新文件中。 但是,在我的日志文件监视过程移动文件后,err.log或run.log永远不会再次创build,尽pipemyprog继续运行时没有任何问题。
这是在Linux的正常行为? 如果是这样,我该怎么做才能使我的预期行为起作用?
是的。 除非您第一次程序重新打开文件,否则即使您不能再访问它,也会继续写入旧文件。 实际上,被删除的文件所使用的空间只有在每个进程关闭之后才可用。 如果重新打开它是不可能的(即不能更改可执行文件,也不能重新启动它),那么像http://httpd.apache.org/docs/2.4/programs/rotatelogs.html这样的解决方案是最好的选择。 它可以根据文件大小或时间旋转日志,甚至可以在旋转后调用自定义脚本。
用法示例:
myprog | rotatelogs logname.log 50M
这样,只要大小达到50兆字节,日志就会被旋转。
[编辑:指向更新版本的rotatelogs]
如果我不得不猜测,它实际上是将记录的进程与文件描述符相关联,而不是文件名。 当您重命名它时,您只更改文件名称。 所以这个过程只是记录到文件。 只是一个猜测。 如果我负责解决这个问题,我将停止日志记录过程,并在那个时候重新启动,重新将它与正确的文件相关联。
只是一个猜测。
支持日志旋转的软件实际上已经为此轮换写入了支持。 如果你看看man logrotate
,你会注意到一个典型的配置是这样的:
"/var/log/httpd/access.log" /var/log/httpd/error.log { rotate 5 mail www@my.org size 100k sharedscripts postrotate /usr/bin/killall -HUP httpd endscript }
…这就是说,它发送一个HUP信号给程序的日志已被旋转; 该程序有一个信号处理程序 ,重新打开其输出文件。
你也可以在你的shell脚本中这样做:
reopen_logs() { exec >>run.log 2>>err.log } trap reopen_logs HUP
…然后,在旋转日志之后,运行kill -HUP pid_of_yourscript
; 在下一次脚本本身正在执行命令时(因为信号处理程序只在预先执行的可执行程序之间运行),它将重新打开其输出以重新创建日志文件而不需要重新启动。