如何正确使用subprocess启动fdisk子进程,处理中断后继续执行脚本
处理subprocess运行fdisk时的异常,保证脚本持续执行
你的核心需求是在fdisk运行过程中,即使遇到键盘中断(Ctrl+C)或其他错误,脚本仍能继续执行后续的UEFI/BIOS检测逻辑。下面针对你的代码问题给出具体改进方案:
关键问题分析
- 原代码中
subprocess.run()是阻塞式调用,会等待fdisk进程完全结束才继续执行,且process.kill()在run()之后调用毫无意义(子进程已终止)。 BlockDevice类存在缩进错误(__iter__和blockdeviceiter方法嵌套在__init__内),且变量名拼写错误,会导致设备遍历失效。- 缺少异常捕获逻辑,一旦
fdisk被中断或出错,整个脚本会直接崩溃。
改进后的完整代码
#!/usr/bin/env python3 ''' gentoo building basic of the distribution ''' import logging import os import sys import shutil import subprocess from subprocess import Popen, PIPE import json import operator import signal def return_blockdev_name(): # 捕获lsblk执行失败的情况 try: process = subprocess.run( ["lsblk", "--json", "-o", "NAME,SIZE,UUID,MOUNTPOINT,PATH,FSTYPE"], capture_output=True, text=True, check=True ) return json.loads(process.stdout) except subprocess.CalledProcessError as e: print(f"获取块设备信息失败: {e.stderr}") sys.exit(1) class BlockDevice: def __init__(self, block_devices): self.block_devices = block_devices.get("blockdevices", []) # 修复缩进,实现迭代器 def __iter__(self): for device in self.block_devices: yield device def blockdeviceiter(self): return iter(self.block_devices) block_devices = return_blockdev_name() block_device_selection_list = BlockDevice(block_devices) # 打印可用设备,方便用户选择 print("可用块设备列表:") for dev in block_device_selection_list: print(f"名称: {dev['name']}, 路径: {dev['path']}, 大小: {dev['size']}") block_device_selection = input("输入目标USB块设备名称: " ) target_dev = None # 提前找到目标设备,避免循环内重复提示 for item in block_device_selection_list: if item['name'] == block_device_selection: target_dev = item break if target_dev: print(f"已选中设备: {target_dev['name']}, 路径: {target_dev['path']}") fdisk_process = None try: # 用Popen启动fdisk,非阻塞模式 fdisk_process = Popen(['fdisk', target_dev['path']]) # 等待fdisk进程结束 fdisk_process.wait() except KeyboardInterrupt: print("\n用户中断了fdisk,正在终止进程...") if fdisk_process: fdisk_process.kill() fdisk_process.wait() # 确保进程彻底退出,避免僵尸进程 except Exception as e: print(f"运行fdisk时出错: {str(e)}") if fdisk_process: fdisk_process.kill() fdisk_process.wait() else: print("未找到指定的块设备") # 后续逻辑不受前面的错误影响,正常执行 booted = "UEFI" if os.path.exists("/sys/firmware/efi") else "BIOS" print(f"系统启动模式: {booted}") sys.exit(0)
核心修改说明
- 异常捕获机制:用
try-except包裹fdisk的启动和等待逻辑,专门捕获KeyboardInterrupt(用户Ctrl+C)和通用异常,确保脚本不会因中断或错误崩溃。 - 子进程管理优化:改用
subprocess.Popen替代run(),可以在异常发生时主动终止fdisk进程,并用wait()确保进程彻底退出。 - BlockDevice类修复:修正方法缩进和变量名拼写错误,让设备遍历逻辑正常工作。
- 用户体验优化:提前打印可用设备列表,简化用户选择流程;先找到目标设备再执行操作,避免循环内重复输出无效提示。
- 前置错误处理:给
lsblk的调用加上check=True,捕获命令执行失败的情况,提前报错退出。
内容的提问来源于stack exchange,提问作者amadecember
相关产品推荐
相关产品推荐

