意外删除了正在运行的进程“python something.py 2>&1 | tee .log”的日志文件。有没有办法继续保存 tmux 窗格上的输出?

意外删除了正在运行的进程“python something.py 2>&1 | tee .log”的日志文件。有没有办法继续保存 tmux 窗格上的输出?

意外删除了正在运行的进程的日志文件python something.py 2>&1 | tee .log。脚本正在 zsh 上的 tmux 窗格中运行。进程仍在运行但未记录日志。输出本身溢出了 tmux-scrollback-buffer。我能否以某种方式(管理员/sudo 权限)重新启动日志记录进程而无需重新启动进程?

通常我的尝试不会出现问题,代码与安全或任何类型的生产无关,只是复杂的数学计算。因此,这种尝试一直都足够了。

就我目前的情况而言,如果我可以无需重新启动该过程即可再次开始记录,那就太好了。

答案1

只要进程tee持有打开的文件描述符,该文件就会继续存在,并且所有内容仍会记录在那里。您可以通过 /proc 复制来恢复其当前内容:

  1. 查找“tee”进程的 PID。

  2. 使用lsfd -p <PID>lsof -p <PID>ls -l /proc/<PID>/fd查找与打开的文件对应的文件描述符编号。(它甚至会在文件名旁边标记为“(已删除)”。)

    对于诸如“tee”之类的简单程序,第一个打开的文件几乎总是 FD #3,因此本文中的所有示例3也将使用这个文件。

  3. 通过以下方式将文件内容复制到新文件/proc

    cp /proc/<TEE_PID>/fd/3 old.log
    

    (/proc/PID/fd 中的符号链接很特殊 - 打开它们仍然可以解析为正确的文件,即使符号链接看起来已损坏,或者它指向的甚至不是真实文件。)

也可以让“tee”开始写入新文件:

  1. gdb调试器附加到进程:

    $ sudo gdb -p <TEE_PID>
    

    这将暂停“tee”。如果 Python 程序产生的日志输出足以填满管道缓冲区,它也可能暂停(否则它不会注意到)。

  2. 如果还没有,请使用 /proc 技巧来恢复旧日志文件(通过另一个 shell,而不是在 gdb 内部):

    $ cp /proc/<TEE_PID>/fd/3 old.log
    

    通过做这个gdb 已连接(即,当 'tee' 处于暂停状态时),您可以避免在 'cp' 和 open() 之间的间隙期间丢失消息。

  3. 现在使用 gdb 关闭“tee”并重新打开文件:

    (gdb) p (int) close(3)
    $1 = 0
    
    (gdb) p (int) open("new.log", 01|0100|02000, 0666)
    $2 = 3
    
    (gdb) q
    Detach? y
    

    (这些值01|0100|02000等于O_WRONLY|O_CREAT|O_APPEND函数定义文件,这使得 open() 调用的行为类似于>>shell 运算符。)

    对于诸如“tee”之类的简单情况,open() 极不可能为您提供除原始 #3 之外的任何其他文件描述符,因为这是最低的可用 FD。但在某些情况下,对于更复杂的程序(如果存在编号间隙),可能需要调用dup2($2, 3)close($2)手动将新打开的文件移动到所需的 FD。

  4. 旧文件现在将完全消失(因为它已被删除由于最后一个文件句柄已关闭,所以“tee”会在没有注意到任何内容的情况下写入新文件。

注意:它不会打开新文件,而是可能可以使用linkat()它来在不中断任何操作的情况下恢复原始日志文件,但我还没有测试过。(编辑:不幸的是,根据 linkat() 文档,这对于已完全解除链接的文件不起作用。)

相关内容