不小心删除了运行进程的日志文件python something.py 2>&1 | tee .log
。该脚本在 zsh 的 tmux 窗格中运行。该进程仍在运行,但未记录。输出本身会溢出 tmux-scrollback-buffer。我可以以某种方式(管理员/sudo 权限)再次启动日志记录过程而不重新启动该过程吗?
通常我的尝试没有问题,并且代码与安全或任何类型的生产无关,而只是复杂的数学计算。因此,这种尝试一直是足够的。
在我目前的情况下,如果我可以在不重新启动进程的情况下重新开始记录,那就太好了。
只要
tee
进程拥有一个打开的文件描述符,该文件就会继续存在,并且所有内容都仍然记录在那里。您可以通过 /proc 复制它们来恢复其当前内容:找到 'tee' 进程的 PID。
使用
lsfd -p <PID>
或lsof -p <PID>
或ls -l /proc/<PID>/fd
查找与打开的文件对应的文件描述符编号。(它甚至会在文件名旁边标记为“(已删除)”。)使用诸如“tee”之类的简单程序,打开的第一个文件几乎总是 FD #3,因此本文中的所有示例也将使用
3
。通过以下方式将文件的内容复制到新文件
/proc
:(/proc/PID/fd 中的符号链接很特殊——打开它们仍然会解析到正确的文件,即使符号链接看起来已损坏,或者即使它指向的东西甚至不是真正的文件。)
也可以让 'tee' 开始写入新文件:
将
gdb
调试器附加到进程:这将暂停“发球台”。如果 Python 程序产生足够的日志输出来填充管道缓冲区,它也可能会暂停(否则它不会注意到)。
如果你还没有——使用 /proc 技巧来恢复旧的日志文件(通过另一个 shell,而不是从 gdb 中):
通过在附加 gdb之后执行此操作(即,当 'tee' 挂起时),您可以避免在 'cp' 和 open() 之间的间隙期间丢失消息。
现在使用 gdb 关闭 'tee' 并重新打开文件:
(这些值
01|0100|02000
等于O_WRONLY|O_CREAT|O_APPEND
来自fcntl.h,这使得 open() 调用的行为类似于>>
shell 运算符。)对于诸如“tee”之类的简单情况,open() 极不可能为您提供除原始 #3 之外的任何其他文件描述符,因为这是最低的免费 FD。但在某些程序更复杂的情况下(如果有编号间隙),可能需要调用
dup2($2, 3)
并close($2)
手动将新打开的文件移动到所需的 FD。旧文件现在将完全消失(因为它已被删除并且最后一个文件句柄已关闭),但 'tee' 将写入新文件而不会注意到任何内容。
注意:不是打开一个新文件,而是可以使用
linkat()
在不中断任何内容的情况下使原始日志文件存在,但我尚未对此进行测试。(编辑:不幸的是,根据 linkat() 文档,这特别不适用于已完全取消链接的文件。)