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() { 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_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_cores=$(lscpu 2>/dev/null | grep -E '^CPU\(s\):' | awk '{print $2}')
cpu_mhz=$(lscpu 2>/dev/null | grep 'MHz' | awk '{print $4}') # 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 Model:${NC} ${cpu_info:-Unknown}"
echo -e "${GREEN}CPU Cores:${NC} ${cpu_cores:-Unknown}" echo -e "${GREEN}CPU Cores:${NC} ${cpu_cores:-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}" echo -e "${GREEN}CPU MHz:${NC} ${cpu_mhz:-Unknown}"
fi
} }
get_ram_info() { get_ram_info() {
@@ -293,33 +299,29 @@ get_motherboard_info() {
get_memory_details() { get_memory_details() {
echo -e "\n${GREEN}=== Memory DIMM Information ===${NC}" 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 # Print header
printf "%-12s %-12s %-10s %-12s %-20s\n" "Slot" "Size" "Type" "Speed" "Manufacturer" printf "%-12s %-12s %-10s %-12s %-20s\n" "Slot" "Size" "Type" "Speed" "Manufacturer"
printf "%-12s %-12s %-10s %-12s %-20s\n" "----" "----" "----" "-----" "------------" 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 while IFS= read -r line; do
# Detect start of a memory device section # Detect start of a memory device section (may have leading whitespace or not)
if [[ "$line" =~ ^Memory[[:space:]]Device ]]; then if [[ "$line" =~ Memory[[:space:]]+Device$ ]] || [[ "$line" == "Memory Device" ]]; then
# If we have data from previous device, print it # Print previous device if it had valid data
if [[ -n "$locator" && -n "$size" && ! "$size" =~ (No|Not|Installed) ]]; then if [[ -n "$locator" && -n "$size" && ! "$size" =~ ^(No|Not)[[:space:]] ]]; then
printf "%-12s %-12s %-10s %-12s %-20s\n" \ printf "%-12s %-12s %-10s %-12s %-20s\n" \
"${locator:-N/A}" \ "${locator:-N/A}" \
"${size:-N/A}" \ "${size:-N/A}" \
"${type:-N/A}" \ "${type:-N/A}" \
"${speed:-N/A}" \ "${speed:-N/A}" \
"${manufacturer:-N/A}" "${manufacturer:-N/A}"
((dimm_count++))
fi fi
# Reset for new device
# Reset variables for new device locator="" size="" type="" speed="" manufacturer=""
locator=""
size=""
type=""
speed=""
manufacturer=""
in_device=true in_device=true
continue continue
fi fi
@@ -327,62 +329,65 @@ get_memory_details() {
# Skip if not in a device section # Skip if not in a device section
[[ "$in_device" != true ]] && continue [[ "$in_device" != true ]] && continue
# Parse fields (case-insensitive, flexible whitespace) # Parse fields - be very specific to avoid matching wrong lines
if [[ "$line" =~ ^[[:space:]]*Locator:[[:space:]]*(.+)$ ]] && [[ ! "$line" =~ Bank ]]; then # Locator (but not Bank Locator)
if [[ "$line" =~ ^[[:space:]]*Locator:[[:space:]]*(.+)$ ]] && [[ ! "$line" =~ Bank[[:space:]]*Locator ]]; then
locator="${BASH_REMATCH[1]}" locator="${BASH_REMATCH[1]}"
locator="${locator// /_}" # Replace spaces with underscores locator="${locator// /_}"
# Size
elif [[ "$line" =~ ^[[:space:]]*Size:[[:space:]]*(.+)$ ]]; then elif [[ "$line" =~ ^[[:space:]]*Size:[[:space:]]*(.+)$ ]]; then
size="${BASH_REMATCH[1]}" 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]}" type="${BASH_REMATCH[1]}"
# Skip if it's an error or unknown type # Only clear if it's truly unknown
[[ "$type" =~ (Unknown|Error|Correction) ]] && type="" [[ "$type" == "Unknown" ]] && type=""
# Speed (exact field)
elif [[ "$line" =~ ^[[:space:]]*Speed:[[:space:]]*(.+)$ ]]; then elif [[ "$line" =~ ^[[:space:]]*Speed:[[:space:]]*(.+)$ ]]; then
speed="${BASH_REMATCH[1]}" speed="${BASH_REMATCH[1]}"
[[ "$speed" =~ Unknown ]] && speed="" [[ "$speed" == "Unknown" ]] && speed=""
# Manufacturer
elif [[ "$line" =~ ^[[:space:]]*Manufacturer:[[:space:]]*(.+)$ ]]; then elif [[ "$line" =~ ^[[:space:]]*Manufacturer:[[:space:]]*(.+)$ ]]; then
manufacturer="${BASH_REMATCH[1]}" manufacturer="${BASH_REMATCH[1]}"
[[ "$manufacturer" =~ (Unknown|NO DIMM) ]] && manufacturer="" # Clear common placeholder values
[[ "$manufacturer" =~ ^(Unknown|NO[[:space:]]DIMM|Not[[:space:]]Specified)$ ]] && manufacturer=""
fi fi
# Empty line marks end of device section # Empty line or new section marks end
if [[ -z "$line" ]]; then if [[ -z "$line" ]] || [[ "$line" =~ ^Handle ]]; then
in_device=false in_device=false
fi fi
done < <(dmidecode -t memory 2>/dev/null) done < <(dmidecode -t memory 2>/dev/null)
# Print last device if it has data # Print last device if valid
if [[ -n "$locator" && -n "$size" && ! "$size" =~ (No|Not|Installed) ]]; then if [[ -n "$locator" && -n "$size" && ! "$size" =~ ^(No|Not)[[:space:]] ]]; then
printf "%-12s %-12s %-10s %-12s %-20s\n" \ printf "%-12s %-12s %-10s %-12s %-20s\n" \
"${locator:-N/A}" \ "${locator:-N/A}" \
"${size:-N/A}" \ "${size:-N/A}" \
"${type:-N/A}" \ "${type:-N/A}" \
"${speed:-N/A}" \ "${speed:-N/A}" \
"${manufacturer:-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 fi
# Memory summary # Memory summary
echo -e "\n${GREEN}Memory Summary:${NC}" echo -e "\n${GREEN}Memory Summary:${NC}"
# Count slots more reliably # Count slots and populated using simpler grep approach
local total_slots=0 local total_slots populated
local populated=0 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))
while IFS= read -r line; do populated=$(dmidecode -t memory 2>/dev/null | grep "^[[:space:]]*Size:" | grep -cv "No Module\|Not Installed")
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)
echo -e " Total Slots: $total_slots" echo -e " Total Slots: $total_slots"
echo -e " Populated: $populated" echo -e " Populated: $populated"
@@ -452,6 +457,9 @@ get_physical_interfaces() {
# Skip loopback # Skip loopback
[[ "$iface" == "lo" ]] && continue [[ "$iface" == "lo" ]] && continue
# Skip bonding_masters (virtual file, not an interface)
[[ "$iface" == "bonding_masters" ]] && continue
# Skip virtual/firewall interfaces # Skip virtual/firewall interfaces
[[ "$iface" =~ $VIRTUAL_IFACE_PATTERN ]] && continue [[ "$iface" =~ $VIRTUAL_IFACE_PATTERN ]] && continue