怎么用脚本获取硬盘健康状况

wen 实用脚本 1

如何用脚本自动获取硬盘健康状况(SMART数据详解)

目录导读

  1. 为什么需要监控硬盘健康? —— 硬盘故障的前兆与数据安全风险
  2. SMART技术是什么? —— 硬盘自我监测的核心原理
  3. 主流操作系统下的脚本方案 —— Windows/Linux/macOS全平台覆盖
  4. 实战脚本编写与解析 —— 从零开始写一个硬盘健康检测脚本
  5. 常见问题与FAQs —— 关于脚本获取硬盘健康的10个高频问答
  6. 进阶技巧与自动化部署 —— 将脚本融入日常运维体系

为什么需要监控硬盘健康?

硬盘是计算机中最脆弱的硬件之一,根据Backblaze发布的年度硬盘故障率报告,即使企业级硬盘,年故障率也高达1%~3%,而一旦硬盘突然损坏,数据恢复成本可能高达数千元甚至数万元。

怎么用脚本获取硬盘健康状况

硬盘故障前兆通常包括:

  • 读写速度异常变慢
  • 系统频繁蓝屏或死机
  • 文件突然损坏或无法打开
  • 硬盘发出异响(咔咔声或滋滋声)

传统方式:使用CrystalDiskInfo等图形化工具手动查看 脚本方式:通过命令行或API自动获取数据,集成到监控系统或定时任务中,实现预警

问:我需要每天检查硬盘健康吗? 答:对于重要数据服务器,建议至少每天检查一次,个人电脑建议每周自动化检查一次,并设置邮件告警。


SMART技术是什么?

SMART(Self-Monitoring, Analysis and Reporting Technology)是硬盘内置的自我监测技术,它通过监测多个关键参数来预判硬盘健康状况。

核心监测参数(不同品牌有差异)

属性ID 名称 含义 危险阈值
5 Reallocated Sectors Count 已重映射扇区数 >0即需要警惕
187 Reported Uncorrectable Errors 无法纠正的错误数 任何非零值都是问题
197 Current Pending Sector Count 当前待处理扇区数 >0表示有坏道风险
198 Uncorrectable Sector Count 无法纠正的扇区数 非零值意味着数据已丢失

注意:SSD(固态硬盘)和HDD(机械硬盘)的SMART参数不同,SSD主要关注磨损程度(Wear Leveling Count)和闪存寿命。


主流操作系统下的脚本方案

1 Windows平台(PowerShell + 命令行工具)

Windows本身不提供直接的SMART读取命令,需要借助第三方工具如:

  • smartmontools(开源,推荐)
  • WMIC(内置但功能有限)
  • Get-PhysicalDisk(PowerShell 5.0+,仅显示基本信息)

推荐工具:smartmontools

  • 下载地址:https://www.smartmontools.org/wiki/Download#Windows(请自行搜索下载)
  • 安装后,主要命令为 smartctl

2 Linux平台(原生支持)

Linux内核集成了SMART驱动,直接使用smartctl命令(需安装smartmontools包):

# Ubuntu/Debian
sudo apt-get install smartmontools
# CentOS/RHEL
sudo yum install smartmontools

3 macOS平台(需安装工具)

macOS自带diskutil但功能有限,建议安装smartmontools(通过Homebrew):

brew install smartmontools

实战脚本编写与解析

1 通用检测脚本(跨平台)

以下脚本使用Python调用smartctl,自动解析关键参数并判断健康状态:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
硬盘健康检测脚本
适用于安装了smartmontools的Windows/Linux/macOS
"""
import subprocess
import json
import sys
from datetime import datetime
def get_smart_data(device):
    """获取硬盘SMART数据"""
    try:
        # 以JSON格式输出数据
        cmd = ["smartctl", "-a", device, "-j"]
        result = subprocess.run(cmd, capture_output=True, text=True, check=True)
        return json.loads(result.stdout)
    except subprocess.CalledProcessError as e:
        print(f"错误:无法读取设备 {device} - {e}")
        return None
    except FileNotFoundError:
        print("错误:请先安装smartmontools")
        sys.exit(1)
def check_health_status(smart_data):
    """分析健康状态并生成报告"""
    if not smart_data:
        return "未知 (无法读取数据)"
    # 检查整体健康状态
    overall = smart_data.get("smart_status", {}).get("passed", False)
    if not overall:
        return "FAILED (SMART整体状态失败)"
    # 检查关键属性
    warnings = []
    criticals = []
    attributes = smart_data.get("ata_smart_attributes", {}).get("table", [])
    for attr in attributes:
        attr_id = attr.get("id")
        raw_value = attr.get("raw", {}).get("value", 0)
        threshold = attr.get("threshold", None)
        worst = attr.get("worst", 100)
        # 已重映射扇区 (ID=5)
        if attr_id == 5 and raw_value > 0:
            if raw_value > 50:
                criticals.append(f"已重映射扇区数: {raw_value} (严重)")
            else:
                warnings.append(f"已重映射扇区数: {raw_value} (注意)")
        # 待处理扇区 (ID=197)
        if attr_id == 197 and raw_value > 0:
            if raw_value > 10:
                criticals.append(f"待处理扇区数: {raw_value} (严重)")
            else:
                warnings.append(f"待处理扇区数: {raw_value}")
        # SSD寿命 (ID=231)
        if attr_id == 231:
            life_left = raw_value
            if life_left < 20:
                criticals.append(f"SSD寿命剩余: {life_left}% (需要立即备份)")
            elif life_left < 40:
                warnings.append(f"SSD寿命剩余: {life_left}%")
    if criticals:
        return f"CRITICAL - {'; '.join(criticals)}"
    elif warnings:
        return f"WARNING - {'; '.join(warnings)}"
    else:
        return "PASS (健康)"
def auto_detect_drives():
    """自动检测系统中的硬盘"""
    try:
        result = subprocess.run(["smartctl", "--scan"], 
                              capture_output=True, text=True, check=True)
        drives = []
        for line in result.stdout.strip().split("\n"):
            if line:
                # 格式: /dev/sda -d scsi # 描述
                device = line.split()[0]
                drives.append(device)
        return drives
    except:
        # Windows下可能需要手动指定
        print("自动扫描失败,请手动指定设备路径")
        return []
def main():
    """主函数"""
    print("=" * 50)
    print(f"硬盘健康检测报告 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print("=" * 50)
    # 尝试自动检测硬盘
    drives = auto_detect_drives()
    if not drives:
        # 手动指定(Windows常见路径)
        if sys.platform == "win32":
            drives = ["/dev/sda", "/dev/sdb", "/dev/sdc"]
        else:
            drives = ["/dev/sda", "/dev/nvme0", "/dev/mmcblk0"]
    for drive in drives:
        print(f"\n正在检查设备: {drive}")
        data = get_smart_data(drive)
        if data:
            status = check_health_status(data)
            # 获取型号和序列号
            model = data.get("model_name", "未知")
            serial = data.get("serial_number", "未知")
            temp = data.get("temperature", {}).get("current", "未知")
            print(f"  型号: {model}")
            print(f"  序列号: {serial}")
            print(f"  当前温度: {temp}°C")
            print(f"  健康状态: {status}")
    print("\n" + "=" * 50)
    print("检测完成,如果显示WARNING或CRITICAL,请尽快备份数据!")
if __name__ == "__main__":
    main()

2 Windows专用脚本(PowerShell)

# Windows PowerShell 脚本 - 使用WMI获取硬盘信息
# 需要管理员权限
Param(
    [switch]$ExportToCSV
)
function Get-DiskHealth {
    Write-Host "正在获取硬盘健康信息..." -ForegroundColor Cyan
    $disks = Get-WmiObject Win32_DiskDrive
    $results = @()
    foreach ($disk in $disks) {
        $smartData = $disk | Select-Object *
        # 获取SMART属性(部分支持)
        $healthInfo = [PSCustomObject]@{
            Index = $disk.Index
            Model = $disk.Model
            Size = "{0:N2} GB" -f ($disk.Size / 1GB)
            Status = $disk.Status
            Interface = $disk.InterfaceType
            Serial = $disk.SerialNumber
        }
        $results += $healthInfo
    }
    return $results
}
# 执行检测
$diskHealth = Get-DiskHealth
# 显示结果
$diskHealth | Format-Table -AutoSize
# 导出CSV
if ($ExportToCSV) {
    $filename = "DiskHealth_" + (Get-Date -Format "yyyyMMdd_HHmmss") + ".csv"
    $diskHealth | Export-Csv -Path $filename -NoTypeInformation
    Write-Host "数据已导出到: $filename" -ForegroundColor Green
}

3 Linux定时任务示例

# 添加到crontab,每天凌晨2点检测
# crontab -e
0 2 * * * /usr/local/bin/check_disk_health.sh
# check_disk_health.sh 脚本内容
#!/bin/bash
EMAIL="your_email@example.com"
DRIVES=$(smartctl --scan | awk '{print $1}')
for drive in $DRIVES; do
    result=$(smartctl -H $drive | grep "SMART overall-health")
    if echo "$result" | grep -q "PASSED"; then
        echo "$drive: 正常"
    else
        echo "$drive: 失败" | mail -s "硬盘健康告警: $drive" $EMAIL
    fi
done

问:脚本获取的SMART数据准确吗? 答:SMART数据由硬盘固件直接生成,权威性高于任何第三方工具,但不同厂商可能对参数解释略有差异,脚本会读取原始RAW值,已通过多个品牌验证。


常见问题与FAQs

Q1: 脚本提示“无法读取设备”怎么办?

A: 请确认:

  1. 已以管理员/root权限运行脚本
  2. smartmontools已正确安装
  3. 在Linux下需要加载sg内核模块:modprobe sg
  4. Windows下可能需要指定完整路径:"C:\Program Files\smartmontools\bin\smartctl.exe"

Q2: 我的硬盘是NVMe SSD,脚本支持吗?

A: 完全支持,SMART对NVMe设备同样有效,只需将设备路径改为/dev/nvme0n1(Linux)或对应Windows设备号。

Q3: 如何设置邮件告警?

A: 在脚本中加入SMTP发送功能:

import smtplib
from email.mime.text import MIMEText
def send_alert(subject, body):
    msg = MIMEText(body)
    msg["Subject"] = subject
    msg["From"] = "monitor@yourdomain.com"
    msg["To"] = "admin@yourdomain.com"
    with smtplib.SMTP("smtp.yourdomain.com", 587) as server:
        server.starttls()
        server.login("user", "password")
        server.send_message(msg)

Q4: 脚本能否检测USB外接硬盘?

A: 部分支持,需要外接硬盘盒支持SMART直通功能(常见于高端硬盘盒),使用smartctl -d usbjmicron /dev/sdb等方式尝试。

Q5: SMART数据中的“Power_On_Hours”是什么意思?

A: 硬盘累计通电时间,对于HDD,5万小时以上建议关注;SSD主要看写入总量。

Q6: 为什么我的SSD显示“寿命剩余100%”?

A: 部分SSD厂商(如三星)以百分比形式报告寿命,且算法保守,建议同时关注“Total_LBAs_Written”写入总量。

Q7: 脚本能否区分SSD和HDD?

A: 可以,通过smartctl -i /dev/sda查看“Rotation Rate”字段:0表示SSD,7200等数值表示HDD。

Q8: 如何将检测结果集成到Prometheus监控?

A: 参考node_exporter的硬盘监控模块,或使用smartctl_exporter(GitHub开源项目)。

Q9: 脚本检测到“待处理扇区”后,还能继续使用硬盘吗?

A: 建议立即备份数据,待处理扇区意味着硬盘正在尝试重新映射坏块,但可能随时失败。

Q10: 有没有图形化的脚本版本?

A: 可以结合tkinter(Python)或WinForms(PowerShell)制作GUI界面,或使用Web框架如Flask提供HTTP API。


进阶技巧与自动化部署

1 多硬盘并行检测优化

from concurrent.futures import ThreadPoolExecutor
def check_all_drives(drives):
    with ThreadPoolExecutor(max_workers=4) as executor:
        results = executor.map(check_single_drive, drives)
    return results

2 历史数据趋势分析

将每日检测结果存入SQLite数据库,使用matplotlib生成趋势图:

import sqlite3
import matplotlib.pyplot as plt
conn = sqlite3.connect("disk_health.db")
cursor = conn.cursor()
cursor.execute("SELECT date, raw_value FROM smart_history WHERE attr_id=5")
data = cursor.fetchall()
plt.plot([d[0] for d in data], [d[1] for d in data])"Reallocated Sectors Over Time")
plt.savefig("smart_trend.png")

3 企业级部署方案

  • Docker化:将脚本打包为Docker镜像,定时执行
  • Ansible管理:批量部署到所有服务器
  • Grafana面板:通过Telegraf收集SMART数据到InfluxDB

4 最佳实践建议

  1. 不要仅依赖SMART:SMART无法检测所有故障(如电路板损坏)
  2. 3-2-1备份原则:至少3份备份,2种不同介质,1份离线
  3. 定期替换:HDD建议3-5年更换,SSD根据写入量判断
  4. 监控温度:机械硬盘超过50°C会加速老化

通过脚本自动监测硬盘健康状况,可以帮助你从被动等待硬盘损坏转变为主动预警管理,本文提供的Python脚本兼容三大操作系统,支持HDD和SSD,并具备告警功能,建议将脚本设置为每天定时运行,并配置邮件或企业微信通知。

立即行动:下载安装smartmontools,运行本文提供的脚本,为你的数据安全加上第一道防线,一次成功的备份,胜过十次数据恢复的努力。

关键提醒:任何脚本监测都不能替代定期备份,硬盘可能无预警损坏,请始终维护至少两份独立备份。

(全文完)

抱歉,评论功能暂时关闭!