Created
March 21, 2026 19:07
-
-
Save hed0rah/e671338b8f3076cb6c5688232f13b296 to your computer and use it in GitHub Desktop.
system profile dump
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 | |
| # ============================================================= | |
| # sysprofile — Deep system profile dump | |
| # | |
| # Generates a comprehensive plain-text snapshot of a Linux box. | |
| # Designed to be pasted into AI conversations for full context. | |
| # | |
| # Covers: hardware, kernel, storage, network, GPU, thermal, | |
| # users, services, packages, dev tools, containers, firewalls, | |
| # conda/python/node environments, cron, logs, and more. | |
| # | |
| # Usage: | |
| # sysprofile # Full dump to stdout | |
| # sysprofile --save # Save to ~/sysprofile-<date>.txt | |
| # sysprofile --section hw # Run single section | |
| # sysprofile --list # List available sections | |
| # sysprofile --compact # Shorter output, skip large dumps | |
| # | |
| # Sections: hw cpu mem gpu disk net thermal kernel users | |
| # services firewall pkg dev python conda node | |
| # rust docker containers gpu_proc cron env | |
| # logs dirs perf usb pci bt audio | |
| # ============================================================= | |
| set -uo pipefail | |
| VERSION="1.0.0" | |
| COMPACT=false | |
| SAVE=false | |
| SECTION_FILTER="" | |
| OUTPUT="" | |
| DIVIDER="━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| # Parse args | |
| while [[ $# -gt 0 ]]; do | |
| case "$1" in | |
| --compact) COMPACT=true; shift ;; | |
| --save) SAVE=true; shift ;; | |
| --section) SECTION_FILTER="$2"; shift 2 ;; | |
| --list) | |
| echo "Available sections:" | |
| echo " hw cpu mem gpu disk net thermal kernel users services" | |
| echo " firewall pkg dev python conda node rust docker containers" | |
| echo " gpu_proc cron env logs dirs perf usb pci audio sysctl" | |
| exit 0 ;; | |
| --help|-h) | |
| head -20 "$0" | grep "^#" | sed 's/^# *//' | |
| exit 0 ;; | |
| *) echo "Unknown arg: $1"; exit 1 ;; | |
| esac | |
| done | |
| # Collect output in variable for optional save | |
| emit() { OUTPUT+="$1"$'\n'; echo "$1"; } | |
| section() { emit ""; emit "$DIVIDER"; emit " $1"; emit "$DIVIDER"; } | |
| sub() { emit ""; emit "── $1 ──"; } | |
| kv() { printf -v line " %-24s %s" "$1:" "$2"; emit "$line"; } | |
| run() { eval "$@" 2>/dev/null || echo " [not available]"; } | |
| should_run() { | |
| [[ -z "$SECTION_FILTER" ]] || [[ "$SECTION_FILTER" == "$1" ]] | |
| } | |
| # ═══════════════════════════════════════════════════════════════ | |
| # Header | |
| # ═══════════════════════════════════════════════════════════════ | |
| emit "" | |
| emit " SYSTEM PROFILE — $(hostname) — $(date '+%Y-%m-%d %H:%M:%S %Z')" | |
| emit " sysprofile v${VERSION} $([ "$COMPACT" = true ] && echo '[compact mode]' || echo '[full mode]')" | |
| emit "" | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run hw; then | |
| section "HARDWARE OVERVIEW" | |
| kv "Hostname" "$(hostname)" | |
| kv "Machine ID" "$(cat /etc/machine-id 2>/dev/null || echo 'n/a')" | |
| if [ -f /sys/class/dmi/id/product_name ]; then | |
| kv "Product" "$(cat /sys/class/dmi/id/product_name 2>/dev/null) $(cat /sys/class/dmi/id/product_version 2>/dev/null)" | |
| kv "Manufacturer" "$(cat /sys/class/dmi/id/sys_vendor 2>/dev/null)" | |
| kv "BIOS" "$(cat /sys/class/dmi/id/bios_vendor 2>/dev/null) $(cat /sys/class/dmi/id/bios_version 2>/dev/null) ($(cat /sys/class/dmi/id/bios_date 2>/dev/null))" | |
| fi | |
| if command -v dmidecode &>/dev/null && [ "$(id -u)" -eq 0 ]; then | |
| CHASSIS=$(dmidecode -s chassis-type 2>/dev/null) | |
| [ -n "$CHASSIS" ] && kv "Chassis" "$CHASSIS" | |
| fi | |
| kv "Architecture" "$(uname -m)" | |
| kv "Uptime" "$(uptime -p 2>/dev/null || uptime)" | |
| kv "Boot time" "$(who -b 2>/dev/null | awk '{print $3, $4}')" | |
| kv "Current user" "$(whoami) (uid $(id -u))" | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run cpu; then | |
| section "CPU" | |
| CPU_MODEL=$(lscpu 2>/dev/null | grep "Model name" | sed 's/.*: *//') | |
| CPU_CORES=$(lscpu 2>/dev/null | grep "^CPU(s):" | awk '{print $2}') | |
| CPU_THREADS=$(nproc 2>/dev/null) | |
| CPU_SOCKETS=$(lscpu 2>/dev/null | grep "Socket(s)" | awk '{print $2}') | |
| CPU_CORES_PER=$(lscpu 2>/dev/null | grep "Core(s) per" | awk '{print $4}') | |
| CPU_MAX=$(lscpu 2>/dev/null | grep "CPU max MHz" | awk '{printf "%.1f GHz", $NF/1000}') | |
| CPU_MIN=$(lscpu 2>/dev/null | grep "CPU min MHz" | awk '{printf "%.1f GHz", $NF/1000}') | |
| CPU_ARCH=$(lscpu 2>/dev/null | grep "Architecture" | awk '{print $2}') | |
| CPU_CACHE_L1D=$(lscpu 2>/dev/null | grep "L1d cache" | sed 's/.*: *//') | |
| CPU_CACHE_L1I=$(lscpu 2>/dev/null | grep "L1i cache" | sed 's/.*: *//') | |
| CPU_CACHE_L2=$(lscpu 2>/dev/null | grep "L2 cache" | sed 's/.*: *//') | |
| CPU_CACHE_L3=$(lscpu 2>/dev/null | grep "L3 cache" | sed 's/.*: *//') | |
| CPU_FLAGS=$(lscpu 2>/dev/null | grep "Flags" | sed 's/.*: *//') | |
| CPU_VIRT=$(lscpu 2>/dev/null | grep "Virtualization" | sed 's/.*: *//') | |
| CPU_BYTEORDER=$(lscpu 2>/dev/null | grep "Byte Order" | sed 's/.*: *//') | |
| kv "Model" "$CPU_MODEL" | |
| kv "Sockets / Cores / Threads" "${CPU_SOCKETS:-1} / ${CPU_CORES_PER:-?} / ${CPU_THREADS}" | |
| kv "Frequency" "${CPU_MIN} — ${CPU_MAX}" | |
| kv "Cache L1d/L1i" "${CPU_CACHE_L1D} / ${CPU_CACHE_L1I}" | |
| kv "Cache L2" "$CPU_CACHE_L2" | |
| kv "Cache L3" "$CPU_CACHE_L3" | |
| [ -n "$CPU_VIRT" ] && kv "Virtualization" "$CPU_VIRT" | |
| kv "Byte order" "$CPU_BYTEORDER" | |
| # Current frequency per core | |
| sub "Current Core Frequencies" | |
| if [ -d /sys/devices/system/cpu/cpu0/cpufreq ]; then | |
| for cpu in /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq; do | |
| [ -f "$cpu" ] || continue | |
| core=$(echo "$cpu" | grep -oP 'cpu\d+') | |
| freq=$(cat "$cpu") | |
| governor=$(cat "$(dirname "$cpu")/scaling_governor" 2>/dev/null) | |
| printf -v line " %-8s %4d MHz [%s]" "$core" "$((freq / 1000))" "$governor" | |
| emit "$line" | |
| done | |
| else | |
| emit " [cpufreq data not available]" | |
| fi | |
| # CPU load | |
| sub "CPU Load" | |
| kv "Load average" "$(cat /proc/loadavg)" | |
| if [ "$COMPACT" = false ]; then | |
| sub "Key CPU Flags" | |
| # Extract notable flags | |
| NOTABLE_FLAGS="" | |
| for flag in avx avx2 avx512f sse4_1 sse4_2 aes vmx svm fma f16c; do | |
| echo "$CPU_FLAGS" | grep -qw "$flag" && NOTABLE_FLAGS+="$flag " | |
| done | |
| kv "Notable flags" "${NOTABLE_FLAGS:-none detected}" | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run mem; then | |
| section "MEMORY" | |
| free -h | while IFS= read -r line; do emit " $line"; done | |
| emit "" | |
| if [ "$COMPACT" = false ]; then | |
| sub "Memory Details" | |
| if command -v dmidecode &>/dev/null && [ "$(id -u)" -eq 0 ]; then | |
| dmidecode -t memory 2>/dev/null | grep -E "Size|Type:|Speed:|Manufacturer|Locator:" | head -20 | while IFS= read -r line; do emit " $line"; done | |
| else | |
| # Parse from /proc | |
| kv "MemTotal" "$(grep MemTotal /proc/meminfo | awk '{print $2, $3}')" | |
| kv "MemAvailable" "$(grep MemAvailable /proc/meminfo | awk '{print $2, $3}')" | |
| kv "SwapTotal" "$(grep SwapTotal /proc/meminfo | awk '{print $2, $3}')" | |
| kv "SwapFree" "$(grep SwapFree /proc/meminfo | awk '{print $2, $3}')" | |
| kv "Hugepages Total" "$(grep HugePages_Total /proc/meminfo | awk '{print $2}')" | |
| kv "Dirty" "$(grep "^Dirty:" /proc/meminfo | awk '{print $2, $3}')" | |
| kv "Shmem" "$(grep "^Shmem:" /proc/meminfo | awk '{print $2, $3}')" | |
| fi | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run gpu; then | |
| section "GPU" | |
| # NVIDIA | |
| if command -v nvidia-smi &>/dev/null; then | |
| sub "NVIDIA GPU" | |
| nvidia-smi --query-gpu=name,driver_version,pci.bus_id,memory.total,memory.free,memory.used,temperature.gpu,utilization.gpu,utilization.memory,power.draw,power.limit,clocks.gr,clocks.mem,compute_mode --format=csv,noheader 2>/dev/null | while IFS=',' read -r name driver pci memtot memfree memused temp gutil mutil pdraw plimit cgr cmem cmode; do | |
| kv "Name" "$(echo $name | xargs)" | |
| kv "Driver" "$(echo $driver | xargs)" | |
| kv "PCI Bus" "$(echo $pci | xargs)" | |
| kv "VRAM Total" "$(echo $memtot | xargs)" | |
| kv "VRAM Free" "$(echo $memfree | xargs)" | |
| kv "VRAM Used" "$(echo $memused | xargs)" | |
| kv "Temperature" "$(echo $temp | xargs)C" | |
| kv "GPU Utilization" "$(echo $gutil | xargs)" | |
| kv "Mem Utilization" "$(echo $mutil | xargs)" | |
| kv "Power Draw / Limit" "$(echo $pdraw | xargs) / $(echo $plimit | xargs)" | |
| kv "Clocks (GPU/Mem)" "$(echo $cgr | xargs) / $(echo $cmem | xargs)" | |
| kv "Compute Mode" "$(echo $cmode | xargs)" | |
| done | |
| CUDA_RT=$(nvidia-smi 2>/dev/null | grep "CUDA Version" | awk '{print $9}') | |
| [ -n "$CUDA_RT" ] && kv "CUDA (driver)" "$CUDA_RT" | |
| if [ "$COMPACT" = false ]; then | |
| sub "NVIDIA Processes" | |
| PROCS=$(nvidia-smi --query-compute-apps=pid,name,used_memory --format=csv,noheader 2>/dev/null) | |
| if [ -n "$PROCS" ]; then | |
| echo "$PROCS" | while IFS=',' read -r pid name mem; do | |
| kv "PID $(echo $pid | xargs)" "$(echo $name | xargs) ($(echo $mem | xargs))" | |
| done | |
| else | |
| emit " No GPU processes running" | |
| fi | |
| fi | |
| else | |
| # Check for GPU hardware without drivers | |
| GPU_HW=$(lspci 2>/dev/null | grep -iE "vga|3d|display" | head -5) | |
| if [ -n "$GPU_HW" ]; then | |
| sub "GPU Hardware (no nvidia-smi)" | |
| echo "$GPU_HW" | while IFS= read -r line; do emit " $line"; done | |
| else | |
| emit " No dedicated GPU detected" | |
| fi | |
| fi | |
| # Check for AMD ROCm | |
| if command -v rocm-smi &>/dev/null; then | |
| sub "AMD ROCm GPU" | |
| rocm-smi 2>/dev/null | head -20 | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| # Check for Intel GPU | |
| if [ -d /sys/class/drm/card0 ] && [ ! -f /proc/driver/nvidia/version ]; then | |
| sub "Integrated GPU" | |
| for card in /sys/class/drm/card*/; do | |
| if [ -f "${card}device/vendor" ]; then | |
| vendor=$(cat "${card}device/vendor" 2>/dev/null) | |
| device=$(cat "${card}device/device" 2>/dev/null) | |
| kv "$(basename $card)" "vendor=$vendor device=$device" | |
| fi | |
| done | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run disk; then | |
| section "STORAGE" | |
| sub "Filesystems" | |
| df -hT 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| sub "Block Devices" | |
| lsblk -o NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,MODEL,ROTA,RQ-SIZE 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| if [ "$COMPACT" = false ]; then | |
| sub "Disk I/O Stats" | |
| if [ -f /proc/diskstats ]; then | |
| iostat -dx 1 1 2>/dev/null | tail -n +4 | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| sub "Mount Options" | |
| mount | grep -E "^/dev" | while IFS= read -r line; do emit " $line"; done | |
| # SMART status for NVMe | |
| if command -v nvme &>/dev/null; then | |
| sub "NVMe Health" | |
| for dev in /dev/nvme?; do | |
| [ -b "$dev" ] || continue | |
| emit " Device: $dev" | |
| nvme smart-log "$dev" 2>/dev/null | grep -E "temperature|percentage_used|available_spare|data_units" | while IFS= read -r line; do emit " $line"; done | |
| done | |
| elif command -v smartctl &>/dev/null; then | |
| sub "SMART Status" | |
| for dev in /dev/sd? /dev/nvme?n?; do | |
| [ -b "$dev" ] || continue | |
| SMART=$(sudo smartctl -H "$dev" 2>/dev/null | grep "SMART overall") | |
| [ -n "$SMART" ] && kv "$dev" "$SMART" | |
| done | |
| fi | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run net; then | |
| section "NETWORK" | |
| sub "Interfaces" | |
| ip -brief addr 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| sub "Default Route" | |
| ip route show default 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| sub "DNS" | |
| if [ -f /etc/resolv.conf ]; then | |
| grep -E "^nameserver|^search" /etc/resolv.conf | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| # Wireless info | |
| if command -v iwconfig &>/dev/null; then | |
| sub "Wireless" | |
| iwconfig 2>/dev/null | grep -v "no wireless" | grep -v "^$" | head -10 | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| sub "Listening Ports" | |
| ss -tlnp 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| if [ "$COMPACT" = false ]; then | |
| sub "Established Connections" | |
| ss -tnp state established 2>/dev/null | head -20 | while IFS= read -r line; do emit " $line"; done | |
| sub "Network Stats" | |
| for iface in $(ip -brief link 2>/dev/null | awk '{print $1}' | grep -v lo); do | |
| RX=$(cat /sys/class/net/$iface/statistics/rx_bytes 2>/dev/null || echo 0) | |
| TX=$(cat /sys/class/net/$iface/statistics/tx_bytes 2>/dev/null || echo 0) | |
| RX_H=$(numfmt --to=iec $RX 2>/dev/null || echo "${RX}B") | |
| TX_H=$(numfmt --to=iec $TX 2>/dev/null || echo "${TX}B") | |
| kv "$iface" "RX: $RX_H TX: $TX_H" | |
| done | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run thermal; then | |
| section "THERMALS" | |
| for zone in /sys/class/thermal/thermal_zone*/; do | |
| [ -d "$zone" ] || continue | |
| name=$(cat "${zone}type" 2>/dev/null || echo "unknown") | |
| temp=$(($(cat "${zone}temp" 2>/dev/null || echo 0) / 1000)) | |
| mode=$(cat "${zone}mode" 2>/dev/null || echo "") | |
| policy=$(cat "${zone}policy" 2>/dev/null || echo "") | |
| kv "$name" "${temp}C${mode:+ [$mode]}${policy:+ policy=$policy}" | |
| done | |
| if command -v sensors &>/dev/null && [ "$COMPACT" = false ]; then | |
| sub "lm-sensors" | |
| sensors 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| # Fan speed | |
| for fan in /sys/class/hwmon/hwmon*/fan*_input; do | |
| [ -f "$fan" ] || continue | |
| speed=$(cat "$fan" 2>/dev/null || echo 0) | |
| label=$(cat "$(dirname "$fan")/$(basename "$fan" _input)_label" 2>/dev/null || basename "$fan") | |
| [ "$speed" -gt 0 ] && kv "$label" "${speed} RPM" | |
| done | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run kernel; then | |
| section "KERNEL & OS" | |
| kv "OS" "$(grep PRETTY_NAME /etc/os-release 2>/dev/null | cut -d'"' -f2)" | |
| kv "Kernel" "$(uname -r)" | |
| kv "Kernel version" "$(uname -v)" | |
| kv "Arch" "$(uname -m)" | |
| # Key kernel params | |
| if [ "$COMPACT" = false ]; then | |
| sub "Key sysctl" | |
| for param in vm.swappiness vm.dirty_ratio net.core.somaxconn net.ipv4.ip_forward kernel.pid_max fs.file-max fs.inotify.max_user_watches; do | |
| val=$(sysctl -n "$param" 2>/dev/null) | |
| [ -n "$val" ] && kv "$param" "$val" | |
| done | |
| sub "Kernel Modules (GPU/Net related)" | |
| lsmod 2>/dev/null | grep -iE "nvidia|nouveau|amd|iwl|e1000|r8169|bluetooth|snd" | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| # Bootloader | |
| if [ -d /boot/efi ]; then | |
| kv "Boot mode" "UEFI" | |
| elif [ -d /boot/grub ]; then | |
| kv "Boot mode" "BIOS/Legacy" | |
| fi | |
| # Init system | |
| kv "Init" "$(ps -p 1 -o comm= 2>/dev/null)" | |
| # SELinux / AppArmor | |
| if command -v getenforce &>/dev/null; then | |
| kv "SELinux" "$(getenforce 2>/dev/null)" | |
| elif command -v aa-status &>/dev/null; then | |
| PROFILES=$(sudo aa-status 2>/dev/null | grep "profiles are loaded" | head -1) | |
| kv "AppArmor" "${PROFILES:-installed}" | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run users; then | |
| section "USERS & GROUPS" | |
| sub "Human Users (uid >= 1000)" | |
| awk -F: '$3 >= 1000 && $3 < 65534 {printf " %-16s uid=%-6s gid=%-6s shell=%s home=%s\n", $1, $3, $4, $7, $6}' /etc/passwd | |
| sub "Sudoers" | |
| getent group sudo 2>/dev/null | awk -F: '{print " " $4}' | |
| getent group wheel 2>/dev/null | awk -F: '{print " " $4}' | |
| sub "Currently Logged In" | |
| who 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| sub "User Systemd Services" | |
| systemctl --user list-units --type=service --state=active 2>/dev/null | grep -v "^$" | head -15 | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run services; then | |
| section "SERVICES" | |
| sub "Active Services" | |
| systemctl list-units --type=service --state=active --no-pager --no-legend 2>/dev/null | awk '{printf " %-40s %s\n", $1, $4}' | head -50 | |
| if [ "$COMPACT" = false ]; then | |
| sub "Failed Services" | |
| FAILED=$(systemctl list-units --type=service --state=failed --no-pager --no-legend 2>/dev/null) | |
| if [ -n "$FAILED" ]; then | |
| echo "$FAILED" | while IFS= read -r line; do emit " $line"; done | |
| else | |
| emit " None" | |
| fi | |
| sub "Enabled Services" | |
| systemctl list-unit-files --type=service --state=enabled --no-pager --no-legend 2>/dev/null | awk '{printf " %-40s %s\n", $1, $2}' | head -40 | |
| sub "Timers" | |
| systemctl list-timers --no-pager --no-legend 2>/dev/null | head -15 | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run firewall; then | |
| section "FIREWALL" | |
| if command -v ufw &>/dev/null; then | |
| sub "UFW" | |
| sudo -n ufw status verbose 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| if command -v iptables &>/dev/null && [ "$COMPACT" = false ]; then | |
| sub "iptables (filter)" | |
| sudo -n iptables -L -n --line-numbers 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| if command -v nft &>/dev/null && [ "$COMPACT" = false ]; then | |
| sub "nftables" | |
| sudo -n nft list ruleset 2>/dev/null | head -40 | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run pkg; then | |
| section "PACKAGE MANAGEMENT" | |
| if command -v apt &>/dev/null; then | |
| TOTAL=$(dpkg -l 2>/dev/null | grep "^ii" | wc -l) | |
| kv "dpkg packages" "$TOTAL installed" | |
| kv "apt sources" "$(grep -r "^deb " /etc/apt/sources.list /etc/apt/sources.list.d/ 2>/dev/null | wc -l) repositories" | |
| UPGRADEABLE=$(apt list --upgradeable 2>/dev/null | grep -c "upgradable") | |
| kv "Upgradeable" "$UPGRADEABLE packages" | |
| if [ "$COMPACT" = false ]; then | |
| sub "Recent Installs (last 10)" | |
| grep " install " /var/log/dpkg.log 2>/dev/null | tail -10 | awk '{print " " $1, $2, $4}' 2>/dev/null | |
| fi | |
| fi | |
| if command -v snap &>/dev/null; then | |
| sub "Snaps" | |
| snap list 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| if command -v flatpak &>/dev/null; then | |
| sub "Flatpaks" | |
| flatpak list --columns=name,version 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run dev; then | |
| section "DEVELOPMENT TOOLS" | |
| for tool in gcc g++ clang make cmake gdb git svn hg; do | |
| if command -v "$tool" &>/dev/null; then | |
| ver=$("$tool" --version 2>&1 | head -1) | |
| kv "$tool" "$ver" | |
| fi | |
| done | |
| # Interpreters | |
| for tool in python3 python ruby perl lua java javac go; do | |
| if command -v "$tool" &>/dev/null; then | |
| ver=$("$tool" --version 2>&1 | head -1) | |
| kv "$tool" "$ver" | |
| fi | |
| done | |
| # Shells | |
| sub "Shells" | |
| cat /etc/shells 2>/dev/null | grep -v "^#" | grep -v "^$" | while IFS= read -r line; do emit " $line"; done | |
| kv "Default shell" "$SHELL" | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run python; then | |
| section "PYTHON" | |
| if command -v python3 &>/dev/null; then | |
| kv "python3" "$(python3 --version 2>&1)" | |
| kv "Location" "$(which python3)" | |
| kv "pip" "$(pip3 --version 2>/dev/null || echo 'not installed')" | |
| if [ "$COMPACT" = false ]; then | |
| sub "System Python Packages" | |
| pip3 list 2>/dev/null | head -30 | while IFS= read -r line; do emit " $line"; done | |
| TOTAL_PIP=$(pip3 list 2>/dev/null | tail -n +3 | wc -l) | |
| [ "$TOTAL_PIP" -gt 30 ] && emit " ... and $((TOTAL_PIP - 28)) more" | |
| fi | |
| fi | |
| # Virtual envs | |
| sub "Virtual Environments" | |
| # Check common locations | |
| for vdir in ~/.virtualenvs /opt/venvs; do | |
| if [ -d "$vdir" ]; then | |
| for env in "$vdir"/*/; do | |
| [ -f "${env}bin/python" ] || continue | |
| ver=$("${env}bin/python" --version 2>&1) | |
| kv "$(basename $env)" "$ver ($env)" | |
| done | |
| fi | |
| done | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run conda; then | |
| section "CONDA ENVIRONMENTS" | |
| # Find conda | |
| CONDA_SH="" | |
| for try in "$HOME/miniforge3" "$HOME/miniconda3" "$HOME/anaconda3" /opt/conda; do | |
| [ -f "$try/etc/profile.d/conda.sh" ] && CONDA_SH="$try/etc/profile.d/conda.sh" && break | |
| done | |
| if [ -n "$CONDA_SH" ]; then | |
| source "$CONDA_SH" | |
| kv "Conda" "$(conda --version 2>&1)" | |
| kv "Location" "$(dirname $(dirname $CONDA_SH))" | |
| kv "Active env" "${CONDA_DEFAULT_ENV:-none}" | |
| emit "" | |
| conda env list 2>/dev/null | grep -E "^\w" | grep -v "^#" | while read -r envname envpath; do | |
| [ "$envname" = "base" ] && [ "$COMPACT" = true ] && continue | |
| PYVER=$("${envpath}/bin/python" --version 2>/dev/null || echo "?") | |
| ENVSIZE=$(du -sh "$envpath" 2>/dev/null | awk '{print $1}') | |
| PKGCOUNT=$("${envpath}/bin/pip" list 2>/dev/null | tail -n +3 | wc -l) | |
| emit " ▸ ${envname} (${PYVER}, ${ENVSIZE}, ${PKGCOUNT} pip packages)" | |
| if [ "$COMPACT" = false ]; then | |
| # Show all pip packages | |
| "${envpath}/bin/pip" list --format=columns 2>/dev/null | tail -n +3 | while read -r pkg ver rest; do | |
| emit " ${pkg} ${ver}" | |
| done | |
| emit "" | |
| else | |
| # Show key packages only | |
| for pkg in torch tensorflow numpy pandas jupyter jupyterlab langchain openai anthropic faster-whisper flask fastapi; do | |
| ver=$("${envpath}/bin/pip" show "$pkg" 2>/dev/null | grep "^Version:" | awk '{print $2}') | |
| [ -n "$ver" ] && emit " ${pkg} ${ver}" | |
| done | |
| fi | |
| # Check CUDA availability if torch is present | |
| if "${envpath}/bin/pip" show torch &>/dev/null 2>&1; then | |
| CUDA=$("${envpath}/bin/python" -c "import torch; print('CUDA available' if torch.cuda.is_available() else 'CPU only')" 2>/dev/null) | |
| [ -n "$CUDA" ] && emit " [PyTorch: ${CUDA}]" | |
| fi | |
| emit "" | |
| done | |
| # Jupyter kernels | |
| sub "Jupyter Kernels" | |
| KERNEL_DIR="$HOME/.local/share/jupyter/kernels" | |
| if [ -d "$KERNEL_DIR" ]; then | |
| for kdir in "$KERNEL_DIR"/*/; do | |
| [ -f "${kdir}kernel.json" ] || continue | |
| kname=$(basename "$kdir") | |
| kdisp=$(python3 -c "import json; print(json.load(open('${kdir}kernel.json'))['display_name'])" 2>/dev/null || echo "$kname") | |
| kpy=$(python3 -c "import json; print(json.load(open('${kdir}kernel.json'))['argv'][0])" 2>/dev/null || echo "?") | |
| kv "$kdisp" "$kpy" | |
| done | |
| else | |
| emit " No user kernels" | |
| fi | |
| else | |
| emit " Conda not found" | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run node; then | |
| section "NODE.JS" | |
| if command -v node &>/dev/null; then | |
| kv "node" "$(node --version)" | |
| kv "npm" "$(npm --version 2>/dev/null)" | |
| kv "Location" "$(which node)" | |
| if command -v npx &>/dev/null; then kv "npx" "$(npx --version 2>/dev/null)"; fi | |
| if command -v yarn &>/dev/null; then kv "yarn" "$(yarn --version 2>/dev/null)"; fi | |
| if command -v pnpm &>/dev/null; then kv "pnpm" "$(pnpm --version 2>/dev/null)"; fi | |
| if command -v bun &>/dev/null; then kv "bun" "$(bun --version 2>/dev/null)"; fi | |
| sub "Global npm Packages" | |
| npm list -g --depth=0 2>/dev/null | tail -n +2 | while IFS= read -r line; do emit " $line"; done | |
| else | |
| emit " Node.js not installed" | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run rust; then | |
| section "RUST" | |
| if command -v rustc &>/dev/null; then | |
| kv "rustc" "$(rustc --version)" | |
| kv "cargo" "$(cargo --version 2>/dev/null)" | |
| kv "rustup" "$(rustup --version 2>/dev/null | head -1)" | |
| kv "Toolchain" "$(rustup show active-toolchain 2>/dev/null)" | |
| if [ "$COMPACT" = false ]; then | |
| sub "Installed Targets" | |
| rustup target list --installed 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| sub "Cargo Binaries" | |
| ls "$HOME/.cargo/bin/" 2>/dev/null | grep -v "^cargo" | grep -v "^rust" | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| elif [ -d "$HOME/.cargo" ]; then | |
| emit " Rust directory exists but rustc not in PATH" | |
| else | |
| emit " Rust not installed" | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run docker; then | |
| section "DOCKER" | |
| if command -v docker &>/dev/null; then | |
| kv "Docker" "$(docker --version)" | |
| kv "Compose" "$(docker compose version 2>/dev/null || echo 'not available')" | |
| # Docker info (might need sudo) | |
| DINFO=$(docker info 2>/dev/null) | |
| if [ -n "$DINFO" ]; then | |
| kv "Storage driver" "$(echo "$DINFO" | grep "Storage Driver" | awk '{print $3}')" | |
| kv "Docker root" "$(echo "$DINFO" | grep "Docker Root" | awk '{print $NF}')" | |
| kv "Containers" "$(echo "$DINFO" | grep "Containers:" | awk '{print $2}')" | |
| kv "Images" "$(echo "$DINFO" | grep "Images:" | awk '{print $2}')" | |
| # NVIDIA runtime? | |
| echo "$DINFO" | grep -q nvidia && kv "NVIDIA runtime" "available" | |
| fi | |
| sub "Running Containers" | |
| docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| if [ "$COMPACT" = false ]; then | |
| sub "All Containers" | |
| docker ps -a --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Size}}" 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| sub "Images" | |
| docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| sub "Docker Networks" | |
| docker network ls 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| sub "Volumes" | |
| docker volume ls 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| else | |
| emit " Docker not installed" | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run env; then | |
| section "ENVIRONMENT VARIABLES" | |
| sub "Key Variables" | |
| for var in HOME USER SHELL PATH EDITOR DISPLAY WAYLAND_DISPLAY XDG_SESSION_TYPE XDG_CURRENT_DESKTOP LANG LC_ALL TERM SSH_CONNECTION VIRTUAL_ENV CONDA_DEFAULT_ENV CUDA_VISIBLE_DEVICES OLLAMA_HOST; do | |
| val="${!var:-}" | |
| [ -n "$val" ] && kv "$var" "$val" | |
| done | |
| sub "PATH Entries" | |
| echo "$PATH" | tr ':' '\n' | while IFS= read -r p; do | |
| if [ -d "$p" ]; then | |
| count=$(ls "$p" 2>/dev/null | wc -l) | |
| emit " $p ($count entries)" | |
| else | |
| emit " $p [MISSING]" | |
| fi | |
| done | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run cron; then | |
| section "SCHEDULED TASKS" | |
| sub "User Crontab" | |
| crontab -l 2>/dev/null | grep -v "^#" | grep -v "^$" | while IFS= read -r line; do emit " $line"; done | |
| [ -z "$(crontab -l 2>/dev/null | grep -v '^#' | grep -v '^$')" ] && emit " [empty]" | |
| if [ "$COMPACT" = false ]; then | |
| sub "System Crontabs" | |
| for f in /etc/crontab /etc/cron.d/*; do | |
| [ -f "$f" ] || continue | |
| ENTRIES=$(grep -v "^#" "$f" | grep -v "^$" | grep -v "^SHELL" | grep -v "^PATH" | grep -v "^MAILTO") | |
| if [ -n "$ENTRIES" ]; then | |
| emit " [$f]" | |
| echo "$ENTRIES" | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| done | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run dirs; then | |
| section "KEY DIRECTORIES" | |
| for dir in /home/*/ /opt/ /srv/ /var/www/ /var/lib/docker/ /tmp/; do | |
| [ -d "$dir" ] || continue | |
| size=$(du -sh "$dir" 2>/dev/null | awk '{print $1}') | |
| count=$(find "$dir" -maxdepth 1 -mindepth 1 2>/dev/null | wc -l) | |
| kv "$dir" "${size} (${count} items)" | |
| done | |
| # Home directory structure (2 levels) | |
| sub "Home Directory" | |
| if command -v tree &>/dev/null; then | |
| tree -L 2 -d --noreport "$HOME" 2>/dev/null | head -40 | while IFS= read -r line; do emit " $line"; done | |
| else | |
| find "$HOME" -maxdepth 2 -type d 2>/dev/null | head -40 | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run usb; then | |
| section "USB DEVICES" | |
| if command -v lsusb &>/dev/null; then | |
| lsusb 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| else | |
| emit " lsusb not available" | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run pci; then | |
| section "PCI DEVICES (key)" | |
| if command -v lspci &>/dev/null; then | |
| lspci 2>/dev/null | grep -iE "vga|audio|network|ethernet|wifi|usb|nvme|sata|bridge" | while IFS= read -r line; do emit " $line"; done | |
| else | |
| emit " lspci not available" | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run audio; then | |
| section "AUDIO" | |
| if command -v pactl &>/dev/null; then | |
| sub "PulseAudio/PipeWire Sinks" | |
| pactl list sinks short 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| sub "Sources" | |
| pactl list sources short 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| elif command -v aplay &>/dev/null; then | |
| sub "ALSA Devices" | |
| aplay -l 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run logs; then | |
| section "RECENT SYSTEM EVENTS" | |
| sub "Last 15 Journal Entries (priority warning+)" | |
| journalctl -p warning --no-pager -n 15 2>/dev/null | while IFS= read -r line; do emit " $line"; done | |
| sub "Last 5 Logins" | |
| last -5 2>/dev/null | head -6 | while IFS= read -r line; do emit " $line"; done | |
| if [ "$COMPACT" = false ]; then | |
| sub "Auth Failures (last 10)" | |
| journalctl _COMM=sshd --no-pager -n 20 2>/dev/null | grep -i "fail\|invalid\|refused" | tail -10 | while IFS= read -r line; do emit " $line"; done | |
| fi | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| if should_run perf; then | |
| section "PERFORMANCE SNAPSHOT" | |
| sub "Top 10 Processes by CPU" | |
| ps aux --sort=-%cpu | head -11 | while IFS= read -r line; do emit " $line"; done | |
| sub "Top 10 Processes by Memory" | |
| ps aux --sort=-%mem | head -11 | while IFS= read -r line; do emit " $line"; done | |
| sub "Open File Descriptors" | |
| kv "System total" "$(cat /proc/sys/fs/file-nr | awk '{print $1}') / $(cat /proc/sys/fs/file-nr | awk '{print $3}') max" | |
| fi | |
| # ═══════════════════════════════════════════════════════════════ | |
| emit "" | |
| emit "$DIVIDER" | |
| emit " END OF PROFILE — $(hostname) — $(date '+%Y-%m-%d %H:%M:%S %Z')" | |
| emit "$DIVIDER" | |
| emit "" | |
| # Save to file if requested | |
| if [ "$SAVE" = true ]; then | |
| OUTFILE="$HOME/sysprofile-$(date +%Y%m%d-%H%M%S).txt" | |
| echo "$OUTPUT" > "$OUTFILE" | |
| echo "Saved to: $OUTFILE" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment