Python使用Popen结合start /wait执行子进程无法获取退出码求助
问题分析与解决方案
这个问题的核心在于:当你用shell=True执行start /wait命令时,subprocess实际启动的是cmd.exe进程,而你拿到的退出码是这个cmd.exe进程的退出码,不是start命令等待的那个子进程的退出码。
虽然start /wait确实会把被等待进程的退出码设置为当前cmd会话的%ERRORLEVEL%,但默认情况下,cmd.exe退出时并不会把这个%ERRORLEVEL%作为自己的进程退出码返回——除非你明确让它这么做。下面给你两种解决思路:
方案一:修改cmd命令,强制返回正确的退出码
你可以调整命令串,让cmd.exe在执行完start /wait后,主动用%ERRORLEVEL%的值作为自己的退出码。这里需要启用延迟扩展,避免命令行解析时提前替换%ERRORLEVEL%的值:
import subprocess params = {} params['stdout'] = subprocess.PIPE params['stderr'] = subprocess.PIPE params['shell'] = True # 启用延迟扩展,执行start后用正确的ERRORLEVEL退出cmd proc = subprocess.Popen('cmd /v:on /c "start /wait cmd /c exit 1 & exit !ERRORLEVEL!"', **params) resultCode = proc.wait() print(resultCode) # 现在会输出1
方案二:使用subprocess的Windows专属标志(推荐)
不需要依赖start命令,直接用subprocess.CREATE_NEW_CONSOLE标志让子进程在新窗口启动,这样能直接获取子进程的退出码,没有中间层干扰:
import subprocess params = { 'stdout': subprocess.PIPE, 'stderr': subprocess.PIPE, # 启用新控制台窗口的标志(Windows专属) 'creationflags': subprocess.CREATE_NEW_CONSOLE } # 直接启动目标命令,不需要shell=True(除非你的命令依赖shell解析) proc = subprocess.Popen(['cmd', '/c', 'exit', '1'], **params) resultCode = proc.wait() print(resultCode) # 输出1
如果你的实际需求是运行其他程序(比如自定义Python脚本),只需要把['cmd', '/c', 'exit', '1']换成对应的命令列表即可,比如['python', 'your_script.py'],新窗口会正常启动并执行,退出后你能拿到它的真实退出码。
内容的提问来源于stack exchange,提问作者Steve Vermeulen




