- Posted on
- • Artificial Intelligence
Bash Scripts That Diagnose Linux Problems Automatically
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
Bash Scripts That Diagnose Linux Problems Automatically
Ever been paged at 3 a.m. with “the server is slow” and nothing else? The fastest way to resolve incidents is to collect the right facts—immediately, consistently, and without guesswork. Bash can do that for you, on any distro, with minimal dependencies. In this post, you’ll get plug‑and‑play Bash scripts that automatically diagnose common Linux problems, plus guidance on scheduling and packaging the results.
Why automate diagnosis with Bash?
It’s everywhere. Bash ships with virtually every Linux system (bare metal, VM, container).
It reduces mean time to resolution (MTTR). You get a repeatable snapshot of the system, every time, so you can compare “good vs. bad” states.
It preserves volatile evidence. Kernel and service logs can roll over quickly; network state changes second-by-second. Capture them while they’re still hot.
It creates a runbook you can share. Your team can collaborate around proven scripts and stop solving the same mystery twice.
Prerequisites (optional but recommended tools)
The scripts below gracefully degrade if a tool isn’t installed. For best results, install these:
sysstat (iostat, mpstat, pidstat) for I/O and CPU stats
smartmontools (smartctl) for disk health
lsof for open files and listening ports
traceroute for path debugging
DNS utilities (dig) for name resolution checks
ethtool for NIC/link details
Install with your package manager:
Debian/Ubuntu (apt):
sudo apt updatesudo apt install -y sysstat smartmontools lsof traceroute dnsutils ethtool
RHEL/CentOS/Fedora (dnf):
sudo dnf install -y sysstat smartmontools lsof traceroute bind-utils ethtool
openSUSE/SLES (zypper):
sudo zypper install -y sysstat smartmontools lsof traceroute bind-utils ethtool
Note: Some actions (e.g., reading SMART data, firewall rules) require root. Prefix with sudo or run as root.
1) One‑shot system snapshot: collect the facts fast
Drop this script on any host to capture system, service, storage, and network state into a single timestamped tarball.
#!/usr/bin/env bash
# diag-snapshot.sh — collect a structured snapshot for triage
set -Eeuo pipefail
umask 077
TS="$(date +%F-%H%M%S)"
HOST="$(hostname -s 2>/dev/null || echo host)"
BASE_OUT="${OUTDIR:-/var/log/diag}"
OUTDIR="${BASE_OUT}/${HOST}-${TS}"
mkdir -p "$OUTDIR"
log() { echo "[$(date +%T)] $*" | tee -a "$OUTDIR/diag.log"; }
have() { command -v "$1" >/dev/null 2>&1; }
save() { local name="$1"; shift; log "Collect: $name"; { "$@" ; } > "$OUTDIR/$name" 2>&1 || true; }
log "Starting snapshot on $HOST at $TS"
# OS / kernel / uptime / users
save os-release cat /etc/os-release
save uname uname -a
save uptime uptime
save who who -a
# CPU / memory / processes
save cpuinfo cat /proc/cpuinfo
save meminfo cat /proc/meminfo
save top bash -c 'top -b -n1 | head -n 40'
save ps bash -c 'ps aux --sort=-%cpu | head -n 30; echo; ps aux --sort=-%mem | head -n 30'
have vmstat && save vmstat bash -c 'vmstat 1 5'
have mpstat && save mpstat bash -c 'mpstat -P ALL 1 3'
have pidstat && save pidstat bash -c 'pidstat 1 3'
# Filesystems / disks
save df-hT df -hT
save df-inodes df -i
have lsblk && save lsblk lsblk -f
save mounts mount
have iostat && save iostat-x bash -c 'iostat -xz 1 3'
# Disk health (SMART) — requires smartmontools and root
if have smartctl; then
while read -r dev type; do
[[ "$type" == "disk" ]] || continue
d="/dev/$dev"
save "smart-$(basename "$d")" smartctl -H -A "$d"
done < <(lsblk -ndo NAME,TYPE)
fi
# Network
have ip && save ip-a ip -br a
have ip && save ip-route ip r
have ss && save sockets bash -c 'ss -tulpn; echo; ss -s'
have ethtool && save ethtool bash -c 'for i in /sys/class/net/*; do n=$(basename "$i"); ethtool "$n" || true; done'
# Basic connectivity checks
GW="$(ip route 2>/dev/null | awk "/default/ {print \$3; exit}")" || true
[[ -n "${GW:-}" ]] && save ping-gw ping -c 4 -W 2 "$GW"
save ping-8.8.8.8 ping -c 4 -W 2 8.8.8.8
# Services / logs (systemd)
if have systemctl; then
save systemd-failed systemctl --failed
save services-running systemctl list-units --type=service --state=running
fi
if have journalctl; then
save journal-errors journalctl -p 3 -xb --no-pager
fi
have dmesg && save dmesg-warn bash -c 'dmesg -T --level=err,warn || dmesg | tail -n 300'
# Open ports and files
have lsof && save lsof-listen lsof -nP -iTCP -sTCP:LISTEN
# Package versions (quick)
if have rpm; then save packages-rpm rpm -qa --last; fi
if have dpkg; then save packages-deb dpkg -l; fi
if have zypper; then save packages-rpm-zypper zypper se -i; fi
# Bundle results
log "Bundling results"
TARBALL="${OUTDIR}.tgz"
tar -C "$(dirname "$OUTDIR")" -czf "$TARBALL" "$(basename "$OUTDIR")"
log "Done: $TARBALL"
echo "$TARBALL"
How to use:
Save as
diag-snapshot.sh,chmod +x diag-snapshot.sh.Run:
sudo ./diag-snapshot.shIt prints the path to a
.tgzyou can attach to tickets or share internally.
What you’ll capture: hardware/OS basics, CPU/memory/process top talkers, filesystems and I/O, disk SMART health, network state (addresses/routes/sockets), connectivity to gateway and the internet, failed services, and recent high‑priority logs.
2) Network triage in one go
When “the network is slow,” you need to validate DNS, routing, path MTU, and local firewalls. This script does a lightweight, safe check.
#!/usr/bin/env bash
# net-check.sh — quick network triage for a host or IP
set -Eeuo pipefail
TARGET="${1:-8.8.8.8}"
RESOLVER="${RESOLVER:-}"
have() { command -v "$1" >/dev/null 2>&1; }
section() { echo; echo "=== $* ==="; }
section "Target"
echo "Target: $TARGET"
section "Interfaces and routes"
ip -br a || true
ip r || true
section "DNS resolution"
echo "/etc/resolv.conf:"
cat /etc/resolv.conf || true
if have resolvectl; then resolvectl status || true; fi
if have dig; then
dig +short "$TARGET" || true
[[ -n "$RESOLVER" ]] && dig @"$RESOLVER" "$TARGET" +short || true
else
getent ahosts "$TARGET" || true
fi
section "Connectivity (ICMP and PMTU)"
ping -c 4 -W 2 "$TARGET" || true
for s in 1472 1460 1400 1200; do
echo "PMTU probe size=$s"
ping -c 1 -W 2 -M do -s "$s" "$TARGET" || true
done
section "Path trace"
if have traceroute; then
traceroute -n "$TARGET" || true
else
echo "traceroute not installed"
fi
section "Listening/active sockets"
ss -tuna || true
section "Firewall status (best-effort)"
if command -v firewall-cmd >/dev/null 2>&1; then firewall-cmd --state || true; fi
if command -v ufw >/dev/null 2>&1; then ufw status || true; fi
if command -v iptables >/dev/null 2>&1; then iptables -S || true; fi
section "Links"
if command -v ethtool >/dev/null 2>&1; then
for i in /sys/class/net/*; do n=$(basename "$i"); echo "--- $n ---"; ethtool "$n" || true; done
fi
Install missing tools if needed:
apt:
sudo apt install -y traceroute dnsutils ethtooldnf:
sudo dnf install -y traceroute bind-utils ethtoolzypper:
sudo zypper install -y traceroute bind-utils ethtool
Run example:
./net-check.sh example.comRESOLVER=1.1.1.1 ./net-check.sh example.com
3) Service doctor: focus on one systemd unit
Most incidents boil down to “this service misbehaved.” This script pulls the essentials for a single unit: state, recent errors, PID, open ports, and coredumps.
#!/usr/bin/env bash
# service-doctor.sh UNIT — inspect a systemd service
set -Eeuo pipefail
UNIT="${1:-}"
[[ -z "$UNIT" ]] && { echo "Usage: $0 <unit.service>"; exit 1; }
have() { command -v "$1" >/dev/null 2>&1; }
section() { echo; echo "=== $* ==="; }
section "Unit status"
systemctl status --no-pager "$UNIT" || true
section "Restart policy"
systemctl show -p Restart,RestartSec,StartLimitIntervalUSec,StartLimitBurst "$UNIT" || true
section "Recent warnings/errors (last 2h)"
if have journalctl; then
journalctl -u "$UNIT" --since "2 hours ago" -p warning --no-pager || true
fi
section "Main process and binary"
MAINPID=$(systemctl show -p MainPID "$UNIT" | cut -d= -f2 || true)
echo "MainPID: ${MAINPID:-0}"
if [[ -n "${MAINPID:-}" && "$MAINPID" -gt 0 ]]; then
readlink -f "/proc/$MAINPID/exe" || true
echo; echo "Open listening sockets (lsof):"
if have lsof; then lsof -nP -p "$MAINPID" | grep -E 'LISTEN|ESTABLISHED' || true; fi
echo; echo "Environment:"
tr '\0' '\n' < "/proc/$MAINPID/environ" 2>/dev/null | sed 's/^[^=]\+=.*/&/g' || true
fi
section "Coredumps (if any)"
if have coredumpctl; then
coredumpctl list "$UNIT" || true
fi
section "Dependencies"
systemctl list-dependencies "$UNIT" || true
echo
echo "Tip: To restart (if appropriate), run: sudo systemctl restart $UNIT"
Install helpers if needed:
apt:
sudo apt install -y lsofdnf:
sudo dnf install -y lsofzypper:
sudo zypper install -y lsof
Run example:
./service-doctor.sh nginx.service
4) Disk and filesystem triage
Out-of-space or I/O latency incidents are common. This script finds hot spots quickly.
#!/usr/bin/env bash
# disk-doctor.sh [PATH] — find space/inode pressure and disk errors
set -Eeuo pipefail
TARGET="${1:-/}"
have() { command -v "$1" >/dev/null 2>&1; }
section() { echo; echo "=== $* ==="; }
section "Filesystem usage"
df -hT
df -i
section "Largest directories (top 20) under $TARGET"
du -xhd1 "$TARGET" 2>/dev/null | sort -h | tail -n 20
section "I/O stats (if available)"
if have iostat; then iostat -xz 1 3; else echo "iostat not installed (sysstat)"; fi
section "Kernel disk errors"
dmesg -T | egrep -i 'i/o error|ext[234]-fs error|buffer i/o|resetting link|device offlined' || true
section "SMART health (if available; needs root)"
if have smartctl; then
while read -r dev type; do
[[ "$type" == "disk" ]] || continue
echo "--- /dev/$dev ---"
sudo smartctl -H -A "/dev/$dev" || true
done < <(lsblk -ndo NAME,TYPE)
else
echo "smartctl not installed (smartmontools)"
fi
section "Mount options"
mount | cat
Install helpers if needed:
apt:
sudo apt install -y sysstat smartmontoolsdnf:
sudo dnf install -y sysstat smartmontoolszypper:
sudo zypper install -y sysstat smartmontools
Run example:
./disk-doctor.sh /var
Real‑world tip: capture intermittent issues automatically
If an issue occurs sporadically, schedule snapshots so you don’t miss it. With systemd timers:
Create a unit to run the snapshot:
# /etc/systemd/system/diag-snapshot.service
[Unit]
Description=Collect diagnostic snapshot
[Service]
Type=oneshot
ExecStart=/usr/local/bin/diag-snapshot.sh
Create a timer (every 15 minutes, jittered):
# /etc/systemd/system/diag-snapshot.timer
[Unit]
Description=Run diagnostic snapshot periodically
[Timer]
OnBootSec=5m
OnUnitActiveSec=15m
RandomizedDelaySec=2m
Persistent=true
[Install]
WantedBy=timers.target
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable --now diag-snapshot.timer
systemctl list-timers | grep diag-snapshot
This will populate /var/log/diag/*.tgz with time‑stamped bundles you can compare across incidents.
Security and hygiene
Snapshots may contain hostnames, usernames, IPs, and service details. Treat them as internal artifacts and restrict access (the scripts use umask 077).
Consider redacting secrets from environment variables or logs before sharing externally.
Clean up old bundles periodically (e.g., logrotate or a cron/systemd tmpfiles policy).
Conclusion and next steps
Bash remains a powerful, universal tool for incident triage. With these scripts you can:
Capture a consistent, high‑signal snapshot under pressure
Focus quickly on network, service, or disk trouble
Automate evidence collection for flaky, intermittent problems
Your next step:
Install the recommended tools for your distro (apt/dnf/zypper commands above).
Drop these scripts into
/usr/local/bin, make them executable, and test on a non‑production host.Wire up a systemd timer for periodic snapshots on critical systems.
If you found this useful, consider building a small internal repo with your team’s additions (container/runtime checks, GPU stats, Kubernetes node health) and standardize your on‑call runbook around it.