Last active
July 20, 2025 19:58
-
-
Save lanefu/fcf57a0e04289809de428e1e9a7d5fcd to your computer and use it in GitHub Desktop.
smartclt drive hours report
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
echo "Generating Drive Report (Drive Path, Serial Number, Power-On Hours)" | |
echo "-------------------------------------------------------------------" | |
# Get a list of all block devices that are likely physical disks | |
DRIVES=$(lsblk -o KNAME,TYPE -nr | awk '$2=="disk" {print "/dev/"$1}') | |
if [ -z "$DRIVES" ]; then | |
echo "No disk drives found." | |
exit 0 | |
fi | |
# Header for the report | |
printf "%-18s %-25s %s\n" "Drive Path" "Serial Number" "Power-On Hours" | |
printf "%-18s %-25s %s\n" "----------" "-------------" "--------------" | |
for DRIVE_PATH in $DRIVES; do | |
SERIAL_NUMBER="N/A" | |
POWER_ON_HOURS="N/A" # Default to N/A | |
# --- Get Serial Number (using smartctl -i) --- | |
SERIAL_OUTPUT="" | |
if [[ "$DRIVE_PATH" == "/dev/nvme"* ]]; then | |
SERIAL_OUTPUT=$(sudo smartctl -i "$DRIVE_PATH" 2>/dev/null) | |
# Fallback to nvme-cli for serial if smartctl fails or is less reliable | |
if [ $? -ne 0 ] || ! echo "$SERIAL_OUTPUT" | grep -q "Serial Number"; then | |
if command -v nvme >/dev/null 2>&1; then | |
NVME_ID_CTRL=$(sudo nvme id-ctrl "$DRIVE_PATH" 2>/dev/null) | |
if [ $? -eq 0 ] && echo "$NVME_ID_CTRL" | grep -q "sn"; then | |
SERIAL_NUMBER=$(echo "$NVME_ID_CTRL" | grep "sn" | awk '{print $NF}') | |
fi | |
fi | |
fi | |
else | |
SERIAL_OUTPUT=$(sudo smartctl -i -d sat "$DRIVE_PATH" 2>/dev/null) | |
if [ $? -ne 0 ]; then | |
SERIAL_OUTPUT=$(sudo smartctl -i "$DRIVE_PATH" 2>/dev/null) # Try without -d sat | |
fi | |
fi | |
if [ -n "$SERIAL_OUTPUT" ] && [[ "$SERIAL_NUMBER" == "N/A" ]]; then | |
SERIAL_NUMBER=$(echo "$SERIAL_OUTPUT" | grep -i "Serial Number" | awk -F':' '{print $2}' | xargs) | |
fi | |
# --- Get Power-On Hours --- | |
if [[ "$DRIVE_PATH" == "/dev/nvme"* ]]; then | |
# 1. Try nvme-cli first for NVMe drives (most reliable for native NVMe info) | |
if command -v nvme >/dev/null 2>&1; then | |
NVME_SMART_LOG=$(sudo nvme smart-log "$DRIVE_PATH" 2>/dev/null) | |
if [ $? -eq 0 ] && [ -n "$NVME_SMART_LOG" ]; then | |
# Extract Power On Hours (looks for line, splits by ':', takes second field, removes commas, prints) | |
POH_NVME=$(echo "$NVME_SMART_LOG" | grep -E "power_on_hours" | awk -F': ' '{gsub(/,/, "", $2); print $2}' | awk '{print $1}' | xargs) | |
if [ -n "$POH_NVME" ]; then | |
POWER_ON_HOURS="$POH_NVME" | |
else | |
# Extract Controller Busy Time (looks for line, splits by ':', takes second field, removes commas, prints) | |
CBT_NVME=$(echo "$NVME_SMART_LOG" | grep -E "controller_busy_time" | awk -F': ' '{gsub(/,/, "", $2); print $2}' | awk '{print $1}' | xargs) | |
if [ -n "$CBT_NVME" ]; then | |
POWER_ON_HOURS=$((CBT_NVME / 60)) # Convert minutes to hours | |
fi | |
fi | |
fi | |
fi | |
# 2. Fallback to smartctl -A for NVMe if nvme-cli didn't provide hours or isn't installed | |
# The smartctl -A output for NVMe is similar in format to nvme smart-log in your case. | |
if [[ "$POWER_ON_HOURS" == "N/A" ]]; then | |
ATTRIBUTES_OUTPUT=$(sudo smartctl -A "$DRIVE_PATH" 2>/dev/null) | |
if [ -n "$ATTRIBUTES_OUTPUT" ]; then | |
# Extract "Power On Hours:" or "Controller Busy Time:" | |
POH_SMARTCTL_NVME=$(echo "$ATTRIBUTES_OUTPUT" | grep -E "Power On Hours:" | awk -F': ' '{gsub(/,/, "", $2); print $2}' | awk '{print $1}' | xargs) | |
if [ -n "$POH_SMARTCTL_NVME" ]; then | |
POWER_ON_HOURS="$POH_SMARTCTL_NVME" | |
else | |
CBT_SMARTCTL_NVME=$(echo "$ATTRIBUTES_OUTPUT" | grep -E "Controller Busy Time:" | awk -F': ' '{gsub(/,/, "", $2); print $2}' | awk '{print $1}' | xargs) | |
if [ -n "$CBT_SMARTCTL_NVME" ]; then | |
POWER_ON_HOURS=$((CBT_SMARTCTL_NVME / 60)) | |
fi | |
fi | |
fi | |
fi | |
else # Standard SATA/SAS drives (like /dev/sda, /dev/sdb, etc.) | |
ATTRIBUTES_OUTPUT=$(sudo smartctl -A -d sat "$DRIVE_PATH" 2>/dev/null) | |
if [ $? -ne 0 ]; then | |
ATTRIBUTES_OUTPUT=$(sudo smartctl -A "$DRIVE_PATH" 2>/dev/null) # Try without -d sat | |
fi | |
if [ -n "$ATTRIBUTES_OUTPUT" ]; then | |
# For SATA, precisely extract the raw value of Power_On_Hours | |
# This regex captures digits that are either at the end of the line OR | |
# are followed by one or more spaces and an opening parenthesis. | |
RAW_HOURS_VALUE=$(echo "$ATTRIBUTES_OUTPUT" | \ | |
grep -E "^\s*9\s+Power_On_Hours|Power_On_Hours" | \ | |
grep -oP '\s\K\d+(?=\s+\(|\s*$)' | head -n 1) # Gets the number before ( or end of line | |
if [ -n "$RAW_HOURS_VALUE" ]; then | |
# Remove commas, if any (not in your examples, but good practice) | |
CLEAN_HOURS=$(echo "$RAW_HOURS_VALUE" | tr -d ',' | xargs) | |
if [ -n "$CLEAN_HOURS" ]; then | |
POWER_ON_HOURS="$CLEAN_HOURS" | |
fi | |
fi | |
fi | |
fi | |
# Print the results for the current drive | |
printf "%-18s %-25s %s\n" "$DRIVE_PATH" "${SERIAL_NUMBER:-N/A}" "${POWER_ON_HOURS:-N/A}" | |
done | |
echo "-------------------------------------------------------------------" | |
echo "Note: 'N/A' indicates data could not be retrieved (e.g., no SMART support, permission issues, or specific attribute not present)." | |
echo "For NVMe drives, ensure 'nvme-cli' is installed for best results (sudo apt install nvme-cli)." |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
echo "Generating Drive Report for Synology (Drive Path, Serial Number, Power-On Hours)" | |
echo "-------------------------------------------------------------------" | |
# Initialize an array to store detected drive paths | |
declare -a DRIVES | |
# --- Attempt to find Synology-specific SATA/SAS drives (e.g., /dev/sata1, /dev/sata2) --- | |
# Iterate through common Synology SATA device names (e.g., sata1 up to sata24, covering most models) | |
# Adjust the upper limit (e.g., 24) if you have a DiskStation/RackStation with more bays. | |
for DEV_NUM in $(seq 1 24); do # Checks /dev/sata1 to /dev/sata24 | |
DRIVE_PATH="/dev/sata${DEV_NUM}" | |
# Check if the device exists and smartctl can identify it as a disk | |
# smartctl -i will return 0 if it can successfully get info from the device | |
if sudo smartctl -i -d sat "${DRIVE_PATH}" >/dev/null 2>&1 || \ | |
sudo smartctl -i "${DRIVE_PATH}" >/dev/null 2>&1; then | |
DRIVES+=("${DRIVE_PATH}") | |
fi | |
done | |
if [ ${#DRIVES[@]} -eq 0 ]; then | |
echo "No disk drives found using /dev/sataX patterns, or smartctl could not access them." | |
echo "Ensure smartmontools is installed and you have permissions." | |
exit 0 | |
fi | |
# Header for the report | |
printf "%-18s %-25s %s\n" "Drive Path" "Serial Number" "Power-On Hours" | |
printf "%-18s %-25s %s\n" "----------" "-------------" "--------------" | |
for DRIVE_PATH in "${DRIVES[@]}"; do | |
SERIAL_NUMBER="N/A" | |
POWER_ON_HOURS="N/A" | |
# --- Get Serial Number (using smartctl -i) --- | |
SERIAL_OUTPUT=$(sudo smartctl -i -d sat "$DRIVE_PATH" 2>/dev/null) | |
if [ $? -ne 0 ]; then | |
SERIAL_OUTPUT=$(sudo smartctl -i "$DRIVE_PATH" 2>/dev/null) # Try without -d sat | |
fi | |
if [ -n "$SERIAL_OUTPUT" ]; then | |
SERIAL_NUMBER=$(echo "$SERIAL_OUTPUT" | grep -i "Serial Number" | awk -F':' '{print $2}' | xargs) | |
fi | |
# --- Get Power-On Hours (using smartctl -A) --- | |
ATTRIBUTES_OUTPUT=$(sudo smartctl -A -d sat "$DRIVE_PATH" 2>/dev/null) | |
if [ $? -ne 0 ]; then | |
ATTRIBUTES_OUTPUT=$(sudo smartctl -A "$DRIVE_PATH" 2>/dev/null) # Try without -d sat | |
fi | |
if [ -n "$ATTRIBUTES_OUTPUT" ]; then | |
# Common pattern: ID 9, Power_On_Hours | |
POWER_ON_HOURS=$(echo "$ATTRIBUTES_OUTPUT" | grep -E "^\s*9\s+Power_On_Hours" | awk '{print $NF}') | |
# Fallback for other common patterns if ID 9 is not Power_On_Hours | |
if [ -z "$POWER_ON_HOURS" ]; then | |
POWER_ON_HOURS=$(echo "$ATTRIBUTES_OUTPUT" | grep -E "Power_On_Hours" | awk '{print $NF}') | |
fi | |
# Add more specific alternative checks here if you discover them for your Synology drives | |
# For example, if you find "Drive_Uptime_Minutes" in your 'smartctl -a' output: | |
# if [ -z "$POWER_ON_HOURS" ]; then | |
# MINUTES_VAL=$(echo "$ATTRIBUTES_OUTPUT" | grep -E "Drive_Uptime_Minutes" | awk '{print $NF}') | |
# if [ -n "$MINUTES_VAL" ]; then | |
# POWER_ON_HOURS=$((MINUTES_VAL / 60)) | |
# fi | |
# fi | |
fi | |
# Print the results for the current drive | |
printf "%-18s %-25s %s\n" "$DRIVE_PATH" "${SERIAL_NUMBER:-N/A}" "${POWER_ON_HOURS:-N/A}" | |
done | |
echo "-------------------------------------------------------------------" | |
echo "Note: 'N/A' indicates data could not be retrieved (e.g., no SMART support, permission issues, or specific attribute not present)." | |
echo "Synology DSM usually has 'smartmontools' pre-installed." | |
echo "If you still get 'N/A' for some drives, manually inspect 'sudo smartctl -a <drive_path>' for those drives" | |
echo "to identify alternative attribute names for 'Power On Hours'." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment