Python中如何捕获subprocess.call执行子进程时抛出的异常?
问题根本原因
subprocess.call() 本身的设计是不会因为被调用的外部命令执行失败(返回非0退出码)就抛出异常,只有当Python层面无法启动目标命令(比如node不存在、权限不足)时才会触发异常。你遇到的场景是node成功启动,但JS代码运行出错后node返回了非0退出码,subprocess.call()只会把这个退出码作为返回值返回,不会触发异常,因此现有try-except捕获不到。你后续的Python报错是因为JS执行失败后outputs.txt内容不符合预期,后续JSON解析逻辑报错导致的。
解决方案
方案1:直接检查subprocess.call()的返回值
subprocess.call()的返回值等于外部命令的退出码,0代表执行成功,非0代表执行失败:
import subprocess try: print("Running code " + str(sub.id)) # 2>&1是shell语法,把标准错误合并到标准输出一起写入文件,方便后续排查错误 return_code = subprocess.call("node codes.js > outputs.txt 2>&1", shell=True) if return_code != 0: print(f"Error running submission code id {sub.id}, exit code: {return_code}") # 此处添加你的错误处理逻辑,比如跳过后续的JSON解析步骤 except Exception as e: # 此处捕获Python层面启动命令失败的异常,比如node未安装、路径不存在 print(f"Error running submission code id {str(sub.id)}: {str(e)}")
方案2:使用subprocess.check_call()自动抛出异常
如果你希望命令执行失败时直接触发异常走except逻辑,可以用check_call()替代call(),它会在命令返回非0退出码时抛出subprocess.CalledProcessError异常:
import subprocess try: print("Running code " + str(sub.id)) subprocess.check_call("node codes.js > outputs.txt 2>&1", shell=True) except subprocess.CalledProcessError as e: # 捕获外部命令执行失败的异常 print(f"Error running submission code id {sub.id}, exit code: {e.returncode}") except Exception as e: # 捕获其他启动层面的异常 print(f"Error running submission code id {str(sub.id)}: {str(e)}")
进阶方案:直接在Python中捕获输出和错误,无需落盘文件
如果不想把输出写入本地文件,可以用subprocess.run()直接捕获stdout和stderr,同时推荐用列表形式传参避免shell注入风险(尤其适合判题这类用户输入不可控的场景):
import subprocess try: print("Running code " + str(sub.id)) result = subprocess.run( ["node", "codes.js"], capture_output=True, text=True, check=True # 开启后和check_call逻辑一致,非0退出码自动抛异常 ) # 执行成功后再把标准输出写入文件 with open("outputs.txt", "w", encoding="utf-8") as f: f.write(result.stdout) except subprocess.CalledProcessError as e: print(f"Error running submission code id {sub.id}") print(f"JS执行错误详情:{e.stderr}") except Exception as e: print(f"Error running submission code id {str(sub.id)}: {str(e)}")
内容的提问来源于stack exchange,提问作者kofhearts
相关产品推荐
相关产品推荐

