如何用脚本自动获取硬盘健康状况(SMART数据详解)
目录导读
- 为什么需要监控硬盘健康? —— 硬盘故障的前兆与数据安全风险
- SMART技术是什么? —— 硬盘自我监测的核心原理
- 主流操作系统下的脚本方案 —— Windows/Linux/macOS全平台覆盖
- 实战脚本编写与解析 —— 从零开始写一个硬盘健康检测脚本
- 常见问题与FAQs —— 关于脚本获取硬盘健康的10个高频问答
- 进阶技巧与自动化部署 —— 将脚本融入日常运维体系
为什么需要监控硬盘健康?
硬盘是计算机中最脆弱的硬件之一,根据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: 请确认:
- 已以管理员/root权限运行脚本
- smartmontools已正确安装
- 在Linux下需要加载
sg内核模块:modprobe sg - 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 最佳实践建议
- 不要仅依赖SMART:SMART无法检测所有故障(如电路板损坏)
- 3-2-1备份原则:至少3份备份,2种不同介质,1份离线
- 定期替换:HDD建议3-5年更换,SSD根据写入量判断
- 监控温度:机械硬盘超过50°C会加速老化
通过脚本自动监测硬盘健康状况,可以帮助你从被动等待硬盘损坏转变为主动预警管理,本文提供的Python脚本兼容三大操作系统,支持HDD和SSD,并具备告警功能,建议将脚本设置为每天定时运行,并配置邮件或企业微信通知。
立即行动:下载安装smartmontools,运行本文提供的脚本,为你的数据安全加上第一道防线,一次成功的备份,胜过十次数据恢复的努力。
关键提醒:任何脚本监测都不能替代定期备份,硬盘可能无预警损坏,请始终维护至少两份独立备份。
(全文完)