From ef004c621e28e2bcf960f6735160f0b35056c0d7 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Thu, 5 Feb 2026 10:55:55 -0500 Subject: [PATCH] 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 https://code.lotusguild.org/LotusGuild/proxDoc/issues/17 Co-Authored-By: Claude Opus 4.5 --- proxDoc.sh | 132 ++++++++++++++++++++++++++++------------------------- 1 file changed, 70 insertions(+), 62 deletions(-) diff --git a/proxDoc.sh b/proxDoc.sh index 6d3d8a4..58c5315 100755 --- a/proxDoc.sh +++ b/proxDoc.sh @@ -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