Skip to content

Instantly share code, notes, and snippets.

@bjarneo
Created July 5, 2025 14:01
Show Gist options
  • Save bjarneo/e55b52dfabfdb6e1090cb1757d1beaba to your computer and use it in GitHub Desktop.
Save bjarneo/e55b52dfabfdb6e1090cb1757d1beaba to your computer and use it in GitHub Desktop.
dmi_fetch.sh
#!/bin/bash
#
# dmi_fetch.sh
#
# This script gathers system information from `dmidecode` across multiple types
# and presents it in a static, 2x2 'btop'-like dashboard view.
#
# It requires root privileges to run dmidecode and will prompt for them.
#
# Usage: ./dmi_fetch.sh
# --- Color Definitions using tput ---
GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3)
BLUE=$(tput setaf 4)
MAGENTA=$(tput setaf 5)
CYAN=$(tput setaf 6)
WHITE=$(tput setaf 7)
RESET=$(tput sgr0)
BOLD=$(tput bold)
RED=$(tput setaf 1)
# --- Box Drawing Characters ---
BOX_TOP_LEFT="┌"
BOX_TOP_RIGHT="┐"
BOX_BOTTOM_LEFT="└"
BOX_BOTTOM_RIGHT="┘"
BOX_HORIZONTAL="─"
BOX_VERTICAL="│"
# --- Sudo Privilege Check ---
# Prompt for sudo password at the beginning of the script.
if [[ $EUID -ne 0 ]]; then
echo "This script uses 'dmidecode' which requires root privileges."
sudo -v
if [ $? -ne 0 ]; then
echo "${RED}Failed to obtain sudo privileges. Exiting.${RESET}"
exit 1
fi
echo
fi
# --- Helper Functions ---
# Prints the ASCII Art header.
function print_header() {
echo -e "${CYAN}${BOLD}"
echo '▗▄▄▄ ▗▖ ▗▗▄▄▄▗▄▄▄▗▄▄▄▗▄▄▄▗▄▄▗▖ ▗▖'
echo '▐▌ █ ▐▛▚▞▜▌ █ ▐▌ ▐▌ █▐▌ ▐▌ ▐▌'
echo '▐▌ █ ▐▌ ▐▌ █ ▐▛▀▀▐▛▀▀▘ █▐▌ ▐▛▀▜▌'
echo '▐▙▄▄▀ ▐▌ ▐▗▄█▄▐▌ ▐▙▄▄▖ █▝▚▄▄▐▌ ▐▌'
echo -e "${RESET}"
echo
}
# Extracts a specific value from a block of text given a key.
function get_value() {
local key="$1"
local data="$2"
echo -e "$data" | grep -m 1 "$key" | cut -d ':' -f 2- | sed 's/^[[:space:]]*//'
}
# This function generates the formatted lines for a block and stores them in a passed array reference.
# It also returns the calculated width of the block.
# Usage: generate_block_lines "Title" content_array_name output_lines_name output_width_name [fixed_width]
function generate_block_lines() {
local title=" $1 "
local -n content_arr=$2
local -n output_lines=$3
local -n output_width=$4
local fixed_width=${5:-0} # Optional: a pre-determined width to enforce
output_lines=()
output_width=0
local max_width=0
local clean_title
clean_title=$(echo "$title" | sed 's/\x1b\[[0-9;]*m//g')
for line in "${content_arr[@]}"; do
local clean_line
clean_line=$(echo "$line" | sed 's/\x1b\[[0-9;]*m//g')
[[ ${#clean_line} -gt $max_width ]] && max_width=${#clean_line}
done
[[ ${#clean_title} -gt $max_width ]] && max_width=${#clean_title}
max_width=$((max_width + 4))
# If a fixed width is provided and it's larger, use it.
if [[ $fixed_width -gt $max_width ]]; then
max_width=$fixed_width
fi
output_width=$max_width
local top_border="${GREEN}${BOX_TOP_LEFT}${CYAN}${BOLD}${title}${RESET}"
for ((i = ${#clean_title}; i < max_width - 1; i++)); do top_border+="${GREEN}${BOX_HORIZONTAL}"; done
top_border+="${GREEN}${BOX_TOP_RIGHT}${RESET}"
output_lines+=("$top_border")
for line in "${content_arr[@]}"; do
local clean_line
clean_line=$(echo "$line" | sed 's/\x1b\[[0-9;]*m//g')
local padding=$((max_width - ${#clean_line} - 2))
local content_line="${GREEN}${BOX_VERTICAL}${RESET} ${line}"
for ((j = 0; j < padding; j++)); do content_line+=" "; done
content_line+="${GREEN}${BOX_VERTICAL}${RESET}"
output_lines+=("$content_line")
done
local bottom_border="${GREEN}${BOX_BOTTOM_LEFT}"
for ((i = 0; i < max_width - 1; i++)); do bottom_border+="${GREEN}${BOX_HORIZONTAL}"; done
bottom_border+="${GREEN}${BOX_BOTTOM_RIGHT}${RESET}"
output_lines+=("$bottom_border")
}
# --- Data Gathering & Processing ---
echo "${GREEN}Gathering system information...${RESET}"
SYS_INFO=$(sudo dmidecode --type system)
BIOS_INFO=$(sudo dmidecode --type bios)
CPU_INFO=$(sudo dmidecode --type processor)
MEM_INFO=$(sudo dmidecode --type memory)
CHASSIS_INFO=$(sudo dmidecode --type chassis)
# Clear screen for a clean dashboard display
clear
print_header
# --- Panel Generation ---
# Declare arrays and width variables for each panel
declare -a TOP_LEFT_LINES && declare TOP_LEFT_WIDTH
declare -a TOP_RIGHT_LINES && declare TOP_RIGHT_WIDTH
declare -a BOTTOM_LEFT_LINES && declare BOTTOM_LEFT_WIDTH
declare -a BOTTOM_RIGHT_LINES && declare BOTTOM_RIGHT_WIDTH
# Panel 1: System & BIOS
MANUFACTURER=$(get_value "Manufacturer:" "$SYS_INFO")
PRODUCT=$(get_value "Product Name:" "$SYS_INFO")
VERSION=$(get_value "Version:" "$SYS_INFO")
SERIAL=$(get_value "Serial Number:" "$SYS_INFO")
BIOS_VENDOR=$(get_value "Vendor:" "$BIOS_INFO")
BIOS_VERSION=$(get_value "Version:" "$BIOS_INFO")
BIOS_DATE=$(get_value "Release Date:" "$BIOS_INFO")
SYSTEM_BLOCK_CONTENT=(
"${YELLOW}Manufacturer:${WHITE} $MANUFACTURER"
"${YELLOW}Product:${WHITE} $PRODUCT"
"${YELLOW}Version:${WHITE} $VERSION"
"${YELLOW}Serial:${WHITE} $SERIAL"
"${YELLOW}BIOS Vendor:${WHITE} $BIOS_VENDOR"
"${YELLOW}BIOS Version:${WHITE} $BIOS_VERSION"
"${YELLOW}BIOS Date:${WHITE} $BIOS_DATE"
)
generate_block_lines "System & BIOS" SYSTEM_BLOCK_CONTENT TOP_LEFT_LINES TOP_LEFT_WIDTH
# Panel 2: Processor
CPU_VERSION=$(get_value "Version:" "$CPU_INFO")
CPU_MANUFACTURER=$(get_value "Manufacturer:" "$CPU_INFO")
CPU_SPEED=$(get_value "Current Speed:" "$CPU_INFO")
CPU_MAX_SPEED=$(get_value "Max Speed:" "$CPU_INFO")
CORE_COUNT=$(get_value "Core Count:" "$CPU_INFO")
THREAD_COUNT=$(get_value "Thread Count:" "$CPU_INFO")
CPU_BLOCK_CONTENT=(
"${YELLOW}Version:${WHITE} $CPU_VERSION"
"${YELLOW}Manufacturer:${WHITE} $CPU_MANUFACTURER"
"${YELLOW}Speed:${WHITE} $CPU_SPEED"
"${YELLOW}Max Speed:${WHITE} $CPU_MAX_SPEED"
"${YELLOW}Cores / Threads:${WHITE} $CORE_COUNT / $THREAD_COUNT"
)
generate_block_lines "Processor" CPU_BLOCK_CONTENT TOP_RIGHT_LINES TOP_RIGHT_WIDTH
# Panel 3: Memory
declare -a MEMORY_BLOCK_CONTENT
TOTAL_DEVICES=$(get_value "Number Of Devices:" "$MEM_INFO")
MEMORY_BLOCK_CONTENT+=("${YELLOW}Memory Slots:${WHITE} $TOTAL_DEVICES")
current_block=""
while read -r line; do
if [[ "$line" == "Handle "* ]]; then
if [[ -n "$current_block" && "$current_block" =~ "Memory Device" ]]; then
size=$(get_value "Size:" "$current_block")
locator=$(get_value "Locator:" "$current_block")
if [[ "$size" != "No Module Installed" && -n "$size" ]]; then
type=$(get_value "Type:" "$current_block")
speed=$(get_value "Speed:" "$current_block")
manufacturer=$(get_value "Manufacturer:" "$current_block")
MEMORY_BLOCK_CONTENT+=("${MAGENTA} - ${locator:-N/A}:${RESET} ${WHITE}${size:-N/A}, ${type:-N/A}, ${speed:-N/A} (${manufacturer:-N/A})")
elif [[ -n "$locator" ]]; then
MEMORY_BLOCK_CONTENT+=("${BLUE} - ${locator}:${RESET} ${WHITE}Empty")
fi
fi
current_block="$line\n"
else
current_block+="$line\n"
fi
done <<<"$(echo -e "$MEM_INFO\nHandle X")"
generate_block_lines "Memory Devices" MEMORY_BLOCK_CONTENT BOTTOM_LEFT_LINES BOTTOM_LEFT_WIDTH
# --- Dashboard Assembly ---
# This function prints two blocks side-by-side, aligning them correctly.
function print_row() {
local -n left_lines=$1
local left_width=$2
local -n right_lines=$3
local max_height=$((${#left_lines[@]} > ${#right_lines[@]} ? ${#left_lines[@]} : ${#right_lines[@]}))
for ((i = 0; i < max_height; i++)); do
# Use parameter expansion to provide an empty string if the array element doesn't exist.
# This handles rows of different heights gracefully.
printf "%-${left_width}s %s\n" "${left_lines[i]:-}" "${right_lines[i]:-}"
done
}
# Determine max width for the left column to align the two rows vertically
LEFT_COL_WIDTH=$((TOP_LEFT_WIDTH > BOTTOM_LEFT_WIDTH ? TOP_LEFT_WIDTH : BOTTOM_LEFT_WIDTH))
# Re-generate left-column panels if they are narrower than the max width for that column.
# This ensures the boxes in the left column have the same width.
if [[ $TOP_LEFT_WIDTH -lt $LEFT_COL_WIDTH ]]; then
generate_block_lines "System & BIOS" SYSTEM_BLOCK_CONTENT TOP_LEFT_LINES TOP_LEFT_WIDTH $LEFT_COL_WIDTH
fi
if [[ $BOTTOM_LEFT_WIDTH -lt $LEFT_COL_WIDTH ]]; then
generate_block_lines "Memory Devices" MEMORY_BLOCK_CONTENT BOTTOM_LEFT_LINES BOTTOM_LEFT_WIDTH $LEFT_COL_WIDTH
fi
# Print the dashboard rows
print_row TOP_LEFT_LINES $LEFT_COL_WIDTH TOP_RIGHT_LINES
echo
print_row BOTTOM_LEFT_LINES $LEFT_COL_WIDTH BOTTOM_RIGHT_LINES
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment