Fix CPU MHz parsing and memory DIMM display issues

- Fix CPU MHz showing multiple lines by using head -1 and proper regex
- Add CPU max MHz display when available
- Fix memory DIMM table not showing data by improving regex patterns
- Fix Type: field matching other fields like "Type Detail:"
- Filter out bonding_masters from network interfaces list
- Add fallback message when DIMM details cannot be parsed

#17

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-05 10:55:55 -05:00
parent 6125fb9d6b
commit ef004c621e

View File

@@ -210,15 +210,21 @@ get_disk_health() {
}
get_cpu_info() {
local cpu_info cpu_cores cpu_mhz
local cpu_info cpu_cores cpu_mhz cpu_max_mhz
cpu_info=$(grep -m 1 -w 'model name' /proc/cpuinfo 2>/dev/null | awk -F: '{print $2}' | xargs)
cpu_cores=$(lscpu 2>/dev/null | grep '^CPU(s):' | awk '{print $2}')
cpu_mhz=$(lscpu 2>/dev/null | grep 'MHz' | awk '{print $4}')
cpu_cores=$(lscpu 2>/dev/null | grep -E '^CPU\(s\):' | awk '{print $2}')
# Get current CPU MHz (first match only) - handle both "CPU MHz:" and "CPU(s) MHz:" formats
cpu_mhz=$(lscpu 2>/dev/null | grep -E '^CPU( )?(max )?MHz:' | head -1 | awk -F: '{print $2}' | xargs)
cpu_max_mhz=$(lscpu 2>/dev/null | grep -E '^CPU max MHz:' | awk -F: '{print $2}' | xargs)
echo -e "${GREEN}CPU Model:${NC} ${cpu_info:-Unknown}"
echo -e "${GREEN}CPU Cores:${NC} ${cpu_cores:-Unknown}"
echo -e "${GREEN}CPU MHz:${NC} ${cpu_mhz:-Unknown}"
if [[ -n "$cpu_max_mhz" ]]; then
echo -e "${GREEN}CPU MHz:${NC} ${cpu_mhz:-Unknown} (max: ${cpu_max_mhz})"
else
echo -e "${GREEN}CPU MHz:${NC} ${cpu_mhz:-Unknown}"
fi
}
get_ram_info() {
@@ -292,97 +298,96 @@ get_motherboard_info() {
get_memory_details() {
echo -e "\n${GREEN}=== Memory DIMM Information ===${NC}"
# Use a more robust parsing approach
local locator size type speed manufacturer
local in_device=false
# Print header
printf "%-12s %-12s %-10s %-12s %-20s\n" "Slot" "Size" "Type" "Speed" "Manufacturer"
printf "%-12s %-12s %-10s %-12s %-20s\n" "----" "----" "----" "-----" "------------"
local locator="" size="" type="" speed="" manufacturer=""
local in_device=false
local dimm_count=0
while IFS= read -r line; do
# Detect start of a memory device section
if [[ "$line" =~ ^Memory[[:space:]]Device ]]; then
# If we have data from previous device, print it
if [[ -n "$locator" && -n "$size" && ! "$size" =~ (No|Not|Installed) ]]; then
# Detect start of a memory device section (may have leading whitespace or not)
if [[ "$line" =~ Memory[[:space:]]+Device$ ]] || [[ "$line" == "Memory Device" ]]; then
# Print previous device if it had valid data
if [[ -n "$locator" && -n "$size" && ! "$size" =~ ^(No|Not)[[:space:]] ]]; then
printf "%-12s %-12s %-10s %-12s %-20s\n" \
"${locator:-N/A}" \
"${size:-N/A}" \
"${type:-N/A}" \
"${speed:-N/A}" \
"${manufacturer:-N/A}"
((dimm_count++))
fi
# Reset variables for new device
locator=""
size=""
type=""
speed=""
manufacturer=""
# Reset for new device
locator="" size="" type="" speed="" manufacturer=""
in_device=true
continue
fi
# Skip if not in a device section
[[ "$in_device" != true ]] && continue
# Parse fields (case-insensitive, flexible whitespace)
if [[ "$line" =~ ^[[:space:]]*Locator:[[:space:]]*(.+)$ ]] && [[ ! "$line" =~ Bank ]]; then
# Parse fields - be very specific to avoid matching wrong lines
# Locator (but not Bank Locator)
if [[ "$line" =~ ^[[:space:]]*Locator:[[:space:]]*(.+)$ ]] && [[ ! "$line" =~ Bank[[:space:]]*Locator ]]; then
locator="${BASH_REMATCH[1]}"
locator="${locator// /_}" # Replace spaces with underscores
locator="${locator// /_}"
# Size
elif [[ "$line" =~ ^[[:space:]]*Size:[[:space:]]*(.+)$ ]]; then
size="${BASH_REMATCH[1]}"
elif [[ "$line" =~ ^[[:space:]]*Type:[[:space:]]*(.+)$ ]]; then
# Type (exact match, not Type Detail or other Type fields)
elif [[ "$line" =~ ^[[:space:]]*Type:[[:space:]]*([A-Za-z0-9]+)$ ]]; then
type="${BASH_REMATCH[1]}"
# Skip if it's an error or unknown type
[[ "$type" =~ (Unknown|Error|Correction) ]] && type=""
# Only clear if it's truly unknown
[[ "$type" == "Unknown" ]] && type=""
# Speed (exact field)
elif [[ "$line" =~ ^[[:space:]]*Speed:[[:space:]]*(.+)$ ]]; then
speed="${BASH_REMATCH[1]}"
[[ "$speed" =~ Unknown ]] && speed=""
[[ "$speed" == "Unknown" ]] && speed=""
# Manufacturer
elif [[ "$line" =~ ^[[:space:]]*Manufacturer:[[:space:]]*(.+)$ ]]; then
manufacturer="${BASH_REMATCH[1]}"
[[ "$manufacturer" =~ (Unknown|NO DIMM) ]] && manufacturer=""
# Clear common placeholder values
[[ "$manufacturer" =~ ^(Unknown|NO[[:space:]]DIMM|Not[[:space:]]Specified)$ ]] && manufacturer=""
fi
# Empty line marks end of device section
if [[ -z "$line" ]]; then
# Empty line or new section marks end
if [[ -z "$line" ]] || [[ "$line" =~ ^Handle ]]; then
in_device=false
fi
done < <(dmidecode -t memory 2>/dev/null)
# Print last device if it has data
if [[ -n "$locator" && -n "$size" && ! "$size" =~ (No|Not|Installed) ]]; then
# Print last device if valid
if [[ -n "$locator" && -n "$size" && ! "$size" =~ ^(No|Not)[[:space:]] ]]; then
printf "%-12s %-12s %-10s %-12s %-20s\n" \
"${locator:-N/A}" \
"${size:-N/A}" \
"${type:-N/A}" \
"${speed:-N/A}" \
"${manufacturer:-N/A}"
((dimm_count++))
fi
# If no DIMMs were printed, show a message
if [[ $dimm_count -eq 0 ]]; then
echo " (Unable to parse DIMM details from dmidecode)"
fi
# Memory summary
echo -e "\n${GREEN}Memory Summary:${NC}"
# Count slots more reliably
local total_slots=0
local populated=0
while IFS= read -r line; do
if [[ "$line" =~ ^[[:space:]]*Locator: ]] && [[ ! "$line" =~ Bank ]]; then
((total_slots++))
fi
done < <(dmidecode -t memory 2>/dev/null)
while IFS= read -r line; do
if [[ "$line" =~ ^[[:space:]]*Size:[[:space:]]*(.+)$ ]]; then
local size_val="${BASH_REMATCH[1]}"
if [[ ! "$size_val" =~ (No|Not|Installed) ]]; then
((populated++))
fi
fi
done < <(dmidecode -t memory 2>/dev/null)
# Count slots and populated using simpler grep approach
local total_slots populated
total_slots=$(dmidecode -t memory 2>/dev/null | grep -c "^[[:space:]]*Locator:" | head -1)
# Subtract Bank Locator lines
local bank_locators
bank_locators=$(dmidecode -t memory 2>/dev/null | grep -c "Bank Locator:")
total_slots=$((total_slots - bank_locators))
populated=$(dmidecode -t memory 2>/dev/null | grep "^[[:space:]]*Size:" | grep -cv "No Module\|Not Installed")
echo -e " Total Slots: $total_slots"
echo -e " Populated: $populated"
@@ -445,16 +450,19 @@ get_physical_interfaces() {
for iface in /sys/class/net/*; do
# Skip if glob didn't match anything
[[ -e "$iface" ]] || continue
# Get just the interface name
iface=$(basename "$iface")
# Skip loopback
[[ "$iface" == "lo" ]] && continue
# Skip bonding_masters (virtual file, not an interface)
[[ "$iface" == "bonding_masters" ]] && continue
# Skip virtual/firewall interfaces
[[ "$iface" =~ $VIRTUAL_IFACE_PATTERN ]] && continue
# This is a physical interface
echo "$iface"
done