使用subprocess运行命令时如何无需等待进程结束即可获取stdout与stderr
原因说明
subprocess.run() 本身为阻塞调用,必须等待目标进程执行结束后才会返回stdout、stderr结果,所以你启动记事本这类不会自动退出的进程时,程序会一直阻塞在该调用位置。
解决方法
替换subprocess.run()为非阻塞的subprocess.Popen()接口,该接口调用后会立刻返回进程对象,不需要等待进程结束,你可以自行控制输出读取、进程状态检查逻辑。
代码修改参考
首先修正原代码缺失的import sys导入,再调整命令执行部分的逻辑:
import socket import subprocess import os import sys # 原代码缺失该导入,执行exit逻辑会报错 HOST = '0.0.0.0' # 原HOST填写错误,修正为监听所有网卡的标准写法 PORT = 8081 server = socket.socket() server.bind((HOST, PORT)) server.listen(1) client, client_addr = server.accept() while True: command = client.recv(4096) command1 = command.decode().strip() print(command1) if command1 != "exit": # 替换run为Popen,不等待进程结束 proc = subprocess.Popen( command1, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True ) # 可选:如果不需要等待输出,直接返回执行提示,后续异步处理输出 # 注意:记事本等GUI程序本身没有stdout/stderr输出,无法拿到返回内容 try: # 等待1秒获取输出,如果进程没结束也直接返回 stdout, stderr = proc.communicate(timeout=1) risposta = stdout + stderr except subprocess.TimeoutExpired: # 进程还在运行,返回启动成功提示 risposta = f"命令 {command1} 已启动,进程ID: {proc.pid}\n".encode() if risposta != b"": client.send(risposta) print(risposta) else: v = "Executed " + command1 print(v) client.send(v.encode()) else: client.close() sys.exit()
注意事项
- 如果你执行的是
start notepad.exe这类命令,start是Windows cmd内置命令,它本身会启动独立的子进程,你捕获到的只是start命令的输出,而非记事本的输出;且记事本是GUI程序,默认没有标准输出和标准错误输出,无论用什么方式都拿不到它的输出内容 - 如果需要实时获取长时间运行的命令行程序(如持续ping、日志监听脚本)的输出,需要单独开启线程读取
proc.stdout和proc.stderr流,避免缓冲区被占满导致进程卡住 - 远程执行命令存在严重安全风险,仅可在本地测试或可信环境下使用
内容的提问来源于stack exchange,提问作者Narrow
相关产品推荐
相关产品推荐

