Skip to content

Instantly share code, notes, and snippets.

@marshki
Last active August 4, 2025 19:05
Show Gist options
  • Save marshki/96fe72696f89f1b7533a2c93324368bc to your computer and use it in GitHub Desktop.
Save marshki/96fe72696f89f1b7533a2c93324368bc to your computer and use it in GitHub Desktop.
Parse SMART Monitor test results for bad sector count, drive info.
#!/usr/bin/env bash
#
# smarty_pants
#
# Parse SMART Monitor test results for bad sector count, drive info.
#
# Author: M. Krinitz <mjk235 [at] nyu [dot] edu>
# Date: 04-AUG-2025
# License: MIT
host="$(hostname --fqdn)"
timestamp="$(date +"%b %d %X")"
to=""
cc=""
from=""
subject="SMART_Test_Results@$host"
mail_cmd="mail -s $subject -r $from -c $cc $to"
# Glob regex pattern match to find hard disk drive(s)--HDD(s).
drives=(/dev/[sh]d[a-z]*)
# Check yo privilege.
root_check() {
if [ "$EUID" != "0" ] ; then
printf "%s\n" "Root privileges required. Exiting."
exit 1
fi
}
# Check if `smartctl` command exists on system.
smart_binary_check() {
if ! command -v smartctl &> /dev/null; then
printf "%s\n" "SMART Monitoring Tools NOT installed. Exiting."
exit 1
fi
}
# Check if HDD(s) have SMART capability.
smart_capability_check() {
if smartctl --info "$disk" \
| grep --word-regexp --ignore-case --quiet "device lacks SMART capability."; then
return 1
fi
}
# Enable SMART on drive.
smart_enable() {
smartctl --smart=on --quietmode=silent --device=ata "$disk"
}
# Parse SMART report for bad sector count. If count != zero (0), warn me.
smart_bad_sector_count() {
local disk="$1"
local count
count=$(smartctl --all --device=ata "$disk" | awk '/Reallocated_Sector_Ct/ {print $NF}')
if [[ -z "$count" ]]; then
printf "%s\n" "SMART status: Unable to determine bad sector count on: $disk"
return
fi
if [[ "$count" != "0" ]]; then
printf "%s\n" "SMART status: ---WARNING!!!--- $count BAD SECTORS DETECTED on: $disk!!!"
else
printf "%s\n" "SMART status: No problems detected on: $disk."
fi
}
# Parse SMART info for:
# Model Family, Device Model, Serial Number, User Capacity.
smart_info() {
local disk="$1"
printf "%s\n" ""
smartctl --info --device=ata "$disk" | \
grep -E 'Model Family|Device Model|Serial Number|User Capacity'
printf "%s\n" ""
}
# Get retrieval value.
exit_status() {
printf "%s\n" $retVal
if [[ "$retVal" -ne 0 ]]; then
printf "%s\n" "ACHTUNG!!! Something went wrong, homie."
else
printf "%s\n" "Done. Exiting @ $timestamp."
fi
}
# Wrapper function. Pipe standard ouput to email.
main() {
root_check
smart_binary_check
printf "%s\n" "SMART report for: $host@$timestamp"
for disk in "${drives[@]}"; do
printf "%s\n" "----------"
if ! smart_capability_check "$disk"; then
printf "%s\n" "$disk is NOT SMART capable. Skipping."
continue
fi
smart_enable "$disk"
smart_bad_sector_count "$disk"
smart_info "$disk"
done
}
main "$@" | $mail_cmd
retVal=$?
exit_status
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment