如何让Python脚本等待Linux脚本执行完成后再运行测试?
先给你明确答案:os.system()确实会等待你的Linux脚本完全执行完毕后,才会继续往下走Python代码。不过你的代码里有个容易被忽略的小坑,还有一些可以优化的地方,我慢慢给你说清楚:
1. os.system()的阻塞特性
os.system()是一个阻塞式的调用——它会启动指定的命令,然后暂停当前Python进程的执行,直到这个命令(也就是你的linux_script.sh)运行结束并返回退出状态码。只要你的脚本本身是同步执行的(没有把内部启动的程序放到后台运行),那它一定会等脚本生成好.json文件后,才会执行后续代码。
但如果你的linux_script.sh里用了&把某个生成文件的程序放到后台,那脚本本身会立刻退出,os.system()也会跟着返回,这时候你的测试代码就会因为文件还没生成而失败。这种情况你需要修改脚本,比如在脚本末尾加上wait命令,让它等待所有后台子进程完成后再退出。
2. 你的代码位置有问题
你把os.system('./linux_script.sh')直接写在了测试类的顶层代码里,这会导致在测试类被Python加载的时候就执行脚本,而不是在test_dict方法运行前执行。这可能会导致一些意外情况(比如多次运行测试时脚本被重复执行,或者测试环境准备时机不对)。
正确的做法是利用unittest框架的setUp()或setUpClass()方法:
setUp():每个测试方法执行前都会运行一次setUpClass():整个测试类只运行一次(适合只需要准备一次的操作)
修改后的代码示例:
import os import unittest import json import factory # 假设这是你的自定义模块 class TestDict(unittest.TestCase): @classmethod def setUpClass(cls): # 只执行一次的准备操作:生成文件 + 运行Linux脚本 cls.x = factory.FileGenerator() # 执行脚本并检查是否成功 exit_code = os.system('./linux_script.sh') if exit_code != 0: raise RuntimeError(f"Linux脚本执行失败,退出码:{exit_code}") def test_dict(self): # 先从生成的json文件加载数据 with open('target_file.json', 'r') as f: generated_json = json.load(f) # 假设self.test是你要对比的基准字典 self.assertDictEqual(self.test, generated_json, '两个字典不匹配')
3. 更推荐的替代方案:subprocess模块
os.system()是比较老旧的API,功能有限(无法捕获命令的输出、错误信息等)。Python官方更推荐使用subprocess模块,它更灵活、可控:
import subprocess # ... @classmethod def setUpClass(cls): cls.x = factory.FileGenerator() try: # check=True会在命令执行失败(退出码非0)时抛出异常 subprocess.run('./linux_script.sh', check=True, shell=True) except subprocess.CalledProcessError as e: raise RuntimeError(f"Linux脚本执行出错:{e}") from e
这样你能更方便地处理脚本执行失败的情况,也能捕获输出日志用于调试。
内容的提问来源于stack exchange,提问作者freza19

