Skip to content

Instantly share code, notes, and snippets.

@moul
Last active May 27, 2026 16:36
Show Gist options
  • Select an option

  • Save moul/32675996ca746a2e8367aafcf0461717 to your computer and use it in GitHub Desktop.

Select an option

Save moul/32675996ca746a2e8367aafcf0461717 to your computer and use it in GitHub Desktop.
Cross-platform host probe — emits a TOML report identifying the machine. Source: github.com/moul/nixpkgs/inventory/probe.sh
#!/usr/bin/env bash
# probe.sh — emit a structured TOML report identifying this machine.
#
# Usage:
# curl -sSfL https://gist.github.com/moul/32675996ca746a2e8367aafcf0461717/raw/probe.sh | bash
# ./probe.sh > my-host.toml
#
# Source-of-truth: github.com/moul/nixpkgs/inventory/probe.sh
# Gist mirror: gist.github.com/moul/32675996ca746a2e8367aafcf0461717
#
# Output is TOML on stdout. Paste it back into the central inventory.
# Works on Linux and macOS. No deps beyond coreutils / awk / curl (optional).
set -u
have() { command -v "$1" >/dev/null 2>&1; }
trim() { awk '{$1=$1; print}'; }
# Escape a string for TOML basic-string literal.
tstr() { printf '%s' "${1:-}" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\r//g'; }
OS=$(uname -s)
ARCH=$(uname -m)
KERNEL=$(uname -r)
HOSTNAME=$(hostname -s 2>/dev/null || hostname)
FQDN=$(hostname -f 2>/dev/null || hostname)
CPU_MODEL="unknown"
CPU_LOGICAL=0
CPU_PHYSICAL=0
RAM_GB=0
DISK_GB=0
DISK_USED_PCT=0
UPTIME_SECS=0
VIRT="unknown"
DISTRO="$OS"
case "$OS" in
Linux)
if [ -r /etc/os-release ]; then
. /etc/os-release
DISTRO="${PRETTY_NAME:-${NAME:-Linux}}"
fi
CPU_MODEL=$(awk -F: '/^model name/ {print $2; exit}' /proc/cpuinfo 2>/dev/null | trim)
[ -z "$CPU_MODEL" ] && CPU_MODEL=$(awk -F: '/^Model/ {print $2; exit}' /proc/cpuinfo 2>/dev/null | trim)
CPU_LOGICAL=$(nproc 2>/dev/null || awk '/^processor/ {n++} END {print n+0}' /proc/cpuinfo)
CPU_PHYSICAL=$(awk -F: '/^physical id/ {print $2}' /proc/cpuinfo 2>/dev/null | sort -u | wc -l | trim)
[ "$CPU_PHYSICAL" = "0" ] && CPU_PHYSICAL=1
RAM_KB=$(awk '/^MemTotal/ {print $2}' /proc/meminfo 2>/dev/null)
RAM_GB=$(awk -v k="${RAM_KB:-0}" 'BEGIN {printf "%.1f", k/1024/1024}')
ROOT_INFO=$(df -B1G -P / 2>/dev/null | tail -1)
DISK_GB=$(echo "$ROOT_INFO" | awk '{print $2+0}')
DISK_USED_PCT=$(echo "$ROOT_INFO" | awk '{print $5}' | tr -d '%')
UPTIME_SECS=$(awk '{print int($1)}' /proc/uptime 2>/dev/null)
VIRT=$(systemd-detect-virt 2>/dev/null); [ -z "$VIRT" ] && VIRT="none"
;;
Darwin)
DISTRO="macOS $(sw_vers -productVersion 2>/dev/null) ($(sw_vers -buildVersion 2>/dev/null))"
CPU_MODEL=$(sysctl -n machdep.cpu.brand_string 2>/dev/null)
CPU_LOGICAL=$(sysctl -n hw.logicalcpu 2>/dev/null || echo 0)
CPU_PHYSICAL=$(sysctl -n hw.physicalcpu 2>/dev/null || echo 0)
RAM_BYTES=$(sysctl -n hw.memsize 2>/dev/null || echo 0)
RAM_GB=$(awk -v b="$RAM_BYTES" 'BEGIN {printf "%.1f", b/1024/1024/1024}')
ROOT_INFO=$(df -g / 2>/dev/null | tail -1)
DISK_GB=$(echo "$ROOT_INFO" | awk '{print $2+0}')
DISK_USED_PCT=$(echo "$ROOT_INFO" | awk '{print $5}' | tr -d '%')
BOOT=$(sysctl -n kern.boottime 2>/dev/null | awk -F'[ =,]+' '{print $3}')
NOW=$(date +%s)
UPTIME_SECS=$((NOW - BOOT))
VIRT="physical"
;;
esac
UPTIME_DAYS=$((UPTIME_SECS / 86400))
# Public IP (best-effort, 3s timeout each)
PUBLIC_IP=""
if have curl; then
PUBLIC_IP=$(curl -fsSL --max-time 3 https://ifconfig.me 2>/dev/null \
|| curl -fsSL --max-time 3 https://api.ipify.org 2>/dev/null \
|| true)
fi
# Tailscale
TS_IP=""
TS_HOSTNAME=""
TS_BIN=""
for cand in tailscale /Applications/Tailscale.app/Contents/MacOS/Tailscale /usr/bin/tailscale /usr/local/bin/tailscale; do
if [ -x "$cand" ] || have "$cand"; then TS_BIN="$cand"; break; fi
done
if [ -n "$TS_BIN" ]; then
TS_IP=$("$TS_BIN" ip -4 2>/dev/null | head -1 || true)
TS_HOSTNAME=$("$TS_BIN" status --json 2>/dev/null | awk -F'"' '/"HostName": *"/ {print $4; exit}')
fi
# Primary interface
PRIMARY_IFACE=""
case "$OS" in
Linux) PRIMARY_IFACE=$(ip -4 route show default 2>/dev/null | awk 'NR==1 {print $5}') ;;
Darwin) PRIMARY_IFACE=$(route -n get default 2>/dev/null | awk '/interface:/ {print $2}') ;;
esac
# Notable services (binary present OR running)
SERVICES=""
for svc in docker podman nginx caddy postgres mysqld redis-server tailscaled sshd k3s kubelet zfs btrfs; do
if have "$svc" || pgrep -x "$svc" >/dev/null 2>&1; then
SERVICES="${SERVICES:+$SERVICES, }\"$svc\""
fi
done
# Load avg
LOAD=$(uptime 2>/dev/null | awk -F'load averages?:' '{print $2}' | trim | tr -d ',' | awk '{print $1}')
[ -z "$LOAD" ] && LOAD=0
cat <<EOF
# probe report — generated $(date -u +%Y-%m-%dT%H:%M:%SZ)
# Paste this block into the central inventory.
[host]
hostname = "$(tstr "$HOSTNAME")"
fqdn = "$(tstr "$FQDN")"
os = "$(tstr "$OS")"
arch = "$(tstr "$ARCH")"
kernel = "$(tstr "$KERNEL")"
distro = "$(tstr "$DISTRO")"
virtualization = "$(tstr "$VIRT")"
uptime_days = ${UPTIME_DAYS:-0}
uptime_seconds = ${UPTIME_SECS:-0}
[hardware]
cpu_model = "$(tstr "$CPU_MODEL")"
cpu_physical = ${CPU_PHYSICAL:-0}
cpu_logical = ${CPU_LOGICAL:-0}
ram_gb = ${RAM_GB:-0}
disk_gb = ${DISK_GB:-0}
disk_used_pct = ${DISK_USED_PCT:-0}
load_1min = ${LOAD:-0}
[network]
public_ip = "$(tstr "$PUBLIC_IP")"
tailscale_ip = "$(tstr "$TS_IP")"
tailscale_hostname = "$(tstr "$TS_HOSTNAME")"
primary_iface = "$(tstr "$PRIMARY_IFACE")"
[services]
notable = [${SERVICES}]
[meta]
probed_at = "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
probed_user = "$(tstr "${USER:-${LOGNAME:-unknown}}")"
probe_version = "1"
EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment