Python中如何查看正在运行的脚本进程在做什么,即使原文件已被删除?

某机器可能种马了,看了下,有个 python 进程有可疑.
nobody    6447     1  0 Jun19 ?        00:00:00 python /tmp/aa/1.py 47.104.173.85 3336
但是,查看 /tmp/aa/1.py,已经不存在了.
lsof -p 6447 可疑看到 服务器和 47.104.173.85 3336 之间有通信,但是也是 closed 的
请教下,此种情况,我怎么判断这个脚本是具体是干什么呢?
谢过各位先!

Python中如何查看正在运行的脚本进程在做什么,即使原文件已被删除?

13 回复

cd 到 /proc/6447/fd 目录,里面是你进程 6447 打开的文件描述符, 找到 /tmp/aa/1.py 对应的描述符,用 cat 命令导出到别的地方,然后查看就可以了。


这个问题其实是在问如何调试一个正在运行的Python进程,特别是当它的源文件已经被删除或修改后,我们怎么知道它当前在执行什么。

核心思路是使用inspect模块和faulthandlerinspect模块可以获取活动对象的源代码,而faulthandler可以在进程收到特定信号(如SIGUSR1)时打印出所有线程的当前调用栈。

下面是一个完整的示例。首先,我们创建一个会长时间运行的脚本,并模拟它在运行中被删除的情况。然后,我们通过发送信号来触发堆栈跟踪。

1. 创建被监控的脚本 (long_running_script.py):

#!/usr/bin/env python3
import time
import os
import signal
import faulthandler
import sys

# 启用faulthandler,将跟踪信息输出到标准错误流(stderr)
faulthandler.enable()

# 可选:注册对SIGUSR1信号的处理,当收到此信号时打印所有线程的堆栈。
# 在Linux/Mac上常用 `kill -USR1 <pid>` 来触发。
faulthandler.register(signal.SIGUSR1, file=sys.stderr, all_threads=True)

def some_work():
    """模拟一些工作"""
    for i in range(100):
        print(f"Working... {i}")
        time.sleep(2)

if __name__ == "__main__":
    print(f"Process PID: {os.getpid()}")
    print("Script started. You can now delete this .py file if you want.")
    some_work()

2. 运行这个脚本: 在终端中执行它:

python3 long_running_script.py

它会打印出自己的进程ID (PID),比如 12345

3. 模拟删除源文件: 在另一个终端窗口,删除或移动这个Python文件:

rm long_running_script.py
# 或者 mv long_running_script.py /tmp/

此时,进程仍在运行,但它的源文件已经没了。

4. 查看进程在做什么: 向该进程发送 SIGUSR1 信号。在Linux/Mac上使用 kill 命令:

kill -USR1 12345

在运行脚本的终端里,你会立刻看到类似下面的堆栈跟踪被打印出来,显示了当前所有线程正在执行的代码位置:

Thread 0x00007f8b5c0da700 (most recent call first):
  File "long_running_script.py", line 23 in some_work
  File "long_running_script.py", line 29 in <module>

即使源文件已被删除,只要Python进程当初加载了这些代码(字节码还在内存里),faulthandler 通常仍然能解析出函数名和行号(如果.pyc缓存文件还在的话,信息会更完整)。这直接告诉你进程卡在 some_work 函数的第23行(也就是 time.sleep(2) 那里)。

替代方法:使用 py-spy 进行采样分析(无需修改代码)

如果进程没有预先启用 faulthandler,一个更强大的外部工具是 py-spy。它是一个性能分析器,可以附着到任何运行的Python进程并采样调用栈,完全不需要目标进程做任何准备。

安装后:

pip install py-spy

直接对目标PID进行采样:

py-spy dump -p 12345

或者生成一个实时火焰图:

py-spy top -p 12345

py-spy 即使在没有调试符号或源文件的情况下也能工作,因为它直接读取Python解释器的内存状态。

总结一下:

  • 首选方案:如果条件允许,在编写可能长时间运行或重要的脚本时,预先在代码里启用 faulthandler(就像上面的例子一样)。这是最可靠的内置方法。
  • 通用方案:对于任何正在运行的Python进程(包括第三方应用),使用 py-spy 这个外部工具。它功能强大,无需侵入代码。

一句话建议:用 faulthandler 做内置跟踪,用 py-spy 做外部诊断。

里面没有什么可以打开的.能否在指点下?
<br>total 0<br>lrwx------ 1 nobody nobody 64 Jun 23 11:39 0 -&gt; socket:[1562590214]<br>lrwx------ 1 nobody nobody 64 Jun 23 11:39 1 -&gt; socket:[1562590214]<br>lrwx------ 1 nobody nobody 64 Jun 23 11:39 2 -&gt; socket:[1562590214]<br>lrwx------ 1 nobody nobody 64 Jun 23 11:39 3 -&gt; socket:[1562590214]<br>lrwx------ 1 nobody nobody 64 Jun 23 11:39 4 -&gt; socket:[1562588838]<br>lrwx------ 1 nobody nobody 64 Jun 23 11:39 5 -&gt; socket:[1551223311]<br>lrwx------ 1 nobody nobody 64 Jun 23 11:39 6 -&gt; /dev/ptmx<br>lrwx------ 1 nobody nobody 64 Jun 23 11:39 7 -&gt; socket:[1562583276]<br>lrwx------ 1 nobody nobody 64 Jun 23 11:39 8 -&gt; socket:[1551223324]<br>

抱歉啊,是我想的太简单了。Python 运行脚本并不会持续打开那个脚本,所以它的确已经被删除了。

我找到两个网址你可以看一看:
https://stackoverflow.com/questions/19737358/recovery-deleted-but-running-python-script
https://gist.github.com/simonw/8aa492e59265c1a021f5c5618f9e6b12

如果有解决方法请让我知道。

如果想要恢复这个运行的 python 脚本请用 lsof 命令。恢复了之后如果是 elf 文件的话,我也不知道怎么查看内容。知道的可以告诉我一下

kill 了吧 无法恢复

应该是木马,只能 kill 掉了

lsof 怎么恢复呢,我 lsof 也只能看到 python 的一些模块调用,以及一些网络通信,实在看不到什么有价值的东西

多谢了朋友,看了下,估计可能性很小了,我周一上班在面向搜索了解下

把进程 dump 下来然后导入符号表,把运行时的字节码数据位置找出来然后存成 pyc 反编译一下

测试了下,如果,脚本本身还是在干活的,那可以用 strace 看到具体干了什么
但是我的那个脚本应该只是运行着,但是活应该都干完了,所以,看不到什么东西了
太高深的也不想研究了,暂时到此为止吧,感谢各位朋友!

回到顶部