You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确使用subprocess启动fdisk子进程,处理中断后继续执行脚本

处理subprocess运行fdisk时的异常,保证脚本持续执行

你的核心需求是在fdisk运行过程中,即使遇到键盘中断(Ctrl+C)或其他错误,脚本仍能继续执行后续的UEFI/BIOS检测逻辑。下面针对你的代码问题给出具体改进方案:

关键问题分析

  1. 原代码中subprocess.run()是阻塞式调用,会等待fdisk进程完全结束才继续执行,且process.kill()在run()之后调用毫无意义(子进程已终止)。
  2. BlockDevice类存在缩进错误(__iter__和blockdeviceiter方法嵌套在__init__内),且变量名拼写错误,会导致设备遍历失效。
  3. 缺少异常捕获逻辑,一旦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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 14:56:14