使用subprocess.Popen导致Ubuntu终端输出混乱的问题求助
解决subprocess.Popen终端输出混乱问题
终端输出错乱的核心原因是:Python主进程和agt_internal子进程同时往标准输出(终端)写入内容,两个进程的输出互相抢占,导致内容交织错乱。以下是几种可行的解决方案:
方案1:将子进程输出重定向到文件
如果不需要在终端看到子进程的输出,可以直接把它的标准输出和错误输出写到文件里,彻底避免和主进程的print冲突:
import subprocess import time def start_agt_pmlog(): command = 'sudo ./agt_internal -unilog=PM' args = command.split() # 或用shlex.split,效果一致 print('Starts AGT PMLog') # 打开日志文件,以追加模式写入 with open('/home/boblittle/AGT/agt_log.txt', 'a') as log_file: subprocess.Popen( args, shell=False, cwd="/home/boblittle/AGT/", stdout=log_file, stderr=log_file # 把错误输出也写到同一个文件 ) start_agt_pmlog() time.sleep(10) for i in range(10): print('Good Morning America')
方案2:实时读取子进程输出并统一处理
如果需要在终端看到子进程的输出,同时避免错乱,可以用线程单独读取子进程的输出流,给子进程的输出加上标识(比如[AGT]),确保输出区分开:
import subprocess import time import threading def read_subprocess_output(stream, prefix): # 逐行读取子进程输出并打印 for line in iter(stream.readline, b''): print(f'{prefix} {line.decode().strip()}') def start_agt_pmlog(): command = 'sudo ./agt_internal -unilog=PM' args = command.split() print('Starts AGT PMLog') proc = subprocess.Popen( args, shell=False, cwd="/home/boblittle/AGT/", stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True # 直接以文本模式读取,不用手动decode ) # 启动两个线程分别处理stdout和stderr threading.Thread(target=read_subprocess_output, args=(proc.stdout, '[AGT_OUT]'), daemon=True).start() threading.Thread(target=read_subprocess_output, args=(proc.stderr, '[AGT_ERR]'), daemon=True).start() return proc start_agt_pmlog() time.sleep(10) for i in range(10): print('Good Morning America')
注:设置daemon=True是让线程随主进程退出而结束,避免主进程退出后线程残留。
方案3:等待子进程执行完毕再运行主进程输出
如果不需要子进程在后台运行,可以用subprocess.run替代Popen,等待子进程执行完成后再执行主进程的print:
import subprocess import time def start_agt_pmlog(): command = 'sudo ./agt_internal -unilog=PM' args = command.split() print('Starts AGT PMLog') # run会等待子进程执行完毕 subprocess.run( args, shell=False, cwd="/home/boblittle/AGT/", # 如果需要看子进程输出,去掉下面两行;否则重定向到/dev/null stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL ) start_agt_pmlog() time.sleep(10) for i in range(10): print('Good Morning America')
为什么你之前的修改没解决问题?
你之前用了stdout=subprocess.PIPE和stderr=subprocess.PIPE,但没有读取管道中的内容:
- 子进程的输出会被暂存在管道缓冲区,当缓冲区满时子进程会被阻塞,无法正常运行;
- 而且这种方式并没有解决主进程和子进程同时写终端的问题,只是把子进程的输出暂时存起来了,一旦读取管道内容并打印,还是会和主进程的
print交织。
内容的提问来源于stack exchange,提问作者SHR
相关产品推荐
相关产品推荐

