Skip to content

Instantly share code, notes, and snippets.

@gil00pita
Last active April 27, 2026 11:58
Show Gist options
  • Select an option

  • Save gil00pita/9b00b35f7058a1e2c0592415484774bd to your computer and use it in GitHub Desktop.

Select an option

Save gil00pita/9b00b35f7058a1e2c0592415484774bd to your computer and use it in GitHub Desktop.
Space cleanup in Linux
#!/usr/bin/env bash
# ==============================================================================
# cleanup.sh — Linux System Deep Cleanup Script
# Version : 3.0
# ==============================================================================
#
# DESCRIPTION
# ───────────
# A single-file Bash script that safely removes caches, logs, temp files,
# and build artefacts from common developer tools on any Linux machine.
# Each section is self-contained — if a tool is not installed or a folder
# does not exist the section is silently skipped and the script continues.
#
# USAGE
# ─────
# 1. Download / copy this script to your machine:
# curl -O https://your-host/cleanup.sh # or copy manually
#
# 2. Make it executable (one-time):
# chmod +x cleanup.sh
#
# 3. Run it (sudo is required for system-level cleanups):
# sudo ./cleanup.sh
#
# Or, if you prefer not to run the whole script as root, the script will
# automatically re-invoke itself with sudo when needed.
#
# WHAT IT CLEANS (17 sections)
# ──────────────────────────────
# § 1 Docker
# • Stopped containers (docker container prune)
# • Dangling / unused images (docker image prune)
# • Unused volumes (docker volume prune)
# • Unused networks (docker network prune)
# • Build cache (docker system prune -af --volumes)
#
# § 2 npm
# • HTTP / package cache (~/.npm or custom cache dir)
#
# § 3 Yarn
# • Package cache (~/.yarn/cache)
#
# § 4 pnpm
# • Orphaned store packages (pnpm store prune)
#
# § 5 pip / pip3
# • Wheel & HTTP download cache (~/.cache/pip)
#
# § 6 apt / dnf / yum
# • Downloaded .deb/.rpm files (/var/cache/apt, /var/cache/dnf)
# • Autoremoveable dependencies
#
# § 7 systemd journal
# • Log entries older than 7 days or beyond 100 MB
#
# § 8 /tmp and /var/tmp
# • Files in /tmp not accessed in 7+ days
# • Files in /var/tmp not accessed in 30+ days
#
# § 9 User caches & browser data
# • Thumbnail cache (~/.cache/thumbnails)
# • Chrome cache (~/.cache/google-chrome/…/Cache)
# • Firefox cache (~/.cache/mozilla)
# • Opera cache (~/.cache/opera)
# • Brave cache (~/.cache/BraveSoftware)
# • Vivaldi cache (~/.cache/vivaldi)
# • Desktop Trash (~/.local/share/Trash)
#
# § 10 Snap
# • Old / disabled snap revisions
#
# § 11 Flatpak
# • Unused runtimes (flatpak uninstall --unused)
#
# § 12 Old kernel images [Debian/Ubuntu only]
# • Previous kernel packages (apt autoremove --purge)
#
# § 13 Core dump files
# • core and core.<PID> files found anywhere on disk
#
# § 14 VS Code
# • GPU / shader cache (~/.config/Code/GPUCache)
# • HTTP & code cache (~/.config/Code/Cache, Code Cache)
# • Cached extension VSIXs (~/.config/Code/CachedExtensionVSIXs)
# • Crash reports (~/.config/Code/Crashpad)
# • Internal service logs (~/.config/Code/logs)
# • Hot-exit backups (~/.config/Code/Backups)
# • Old remote server binaries (~/.vscode-server/bin)
# • workspaceStorage >30 days (~/.config/Code/User/workspaceStorage)
#
# § 15 Cursor (AI code editor — VS Code fork)
# • Same cache layout as VS Code under ~/.config/Cursor
# • Extra AI scratch dirs (~/.cursor/cache, logs, tmp)
# • workspaceStorage >30 days (~/.config/Cursor/User/workspaceStorage)
#
# § 16 OpenAI Codex CLI
# • Local response cache (~/.codex/cache)
# • Logs (~/.codex/logs)
# • Temp files (~/.codex/tmp)
# • OpenAI SDK HTTP cache (~/.cache/openai)
# • Session JSON files >30 days (~/.codex/sessions)
#
# § 17 Claude (Anthropic desktop app & Claude Code CLI)
# • Electron GPU / shader cache (~/.config/Claude/GPUCache)
# • Electron HTTP cache (~/.config/Claude/Cache, Code Cache)
# • Crash reports (~/.config/Claude/Crashpad)
# • App logs (~/.config/Claude/logs)
# • CLI cache / logs / tmp (~/.claude/cache, logs, tmp)
# • Generic XDG cache buckets (~/.cache/claude, ~/.cache/anthropic)
# • Conversation logs >30 days (~/.claude/conversations, projects)
#
# WHAT IT DOES NOT TOUCH
# ──────────────────────
# • Your VS Code / Cursor settings, keybindings, or installed extensions
# • Claude Code / Codex conversation history newer than 30 days
# • Any database, source-code, or project files
# • Files owned by other users (runs as the invoking user's $HOME)
#
# NOTES
# ─────
# • Safe to run repeatedly — idempotent, nothing breaks if already clean.
# • Each section prints ✔ (cleaned), ↷ (skipped), or ⚠ (warning).
# • A space-freed summary is printed at the end.
# • Tested on Ubuntu 22.04 / 24.04, Debian 12, Fedora 39, Arch Linux.
#
# ==============================================================================
# -u : error on unset variables
# -o pipefail : catch pipe failures
# NOTE: -e (exit-on-error) is intentionally OMITTED — a missing path or
# unavailable tool must never abort the whole script. Every risky
# operation is guarded with an existence check or || true.
set -uo pipefail
# ── Colours ───────────────────────────────────────────────────────────────────
RED='\033[0;31m'; YELLOW='\033[1;33m'; GREEN='\033[0;32m'
CYAN='\033[0;36m'; BOLD='\033[1m'; RESET='\033[0m'
# ── Helpers ───────────────────────────────────────────────────────────────────
info() { echo -e "${CYAN}$*${RESET}"; }
success() { echo -e "${GREEN}$*${RESET}"; }
warn() { echo -e "${YELLOW}$*${RESET}"; }
header() { echo -e "\n${BOLD}━━━ $* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"; }
skip() { echo -e "${YELLOW} ↷ skipped — $*${RESET}"; }
has() { command -v "$1" &>/dev/null; }
# dir_size PATH — human-readable size, or "0 B" if path absent
dir_size() {
local p="$1"
[[ -e "$p" ]] && du -sh "$p" 2>/dev/null | awk '{print $1}' || echo "0 B"
}
# safe_rm PATH [LABEL]
# Removes a file or directory if it exists; silently skips if not found;
# never aborts the script on permission or other errors.
safe_rm() {
local target="$1"
local label="${2:-$(basename "$target")}"
if [[ -d "$target" ]]; then
local sz; sz=$(dir_size "$target")
info "Removing ${label} (${sz})…"
rm -rf "${target:?}" 2>/dev/null || warn "Could not fully remove ${label} — continuing."
elif [[ -f "$target" ]]; then
info "Removing file: ${label}"
rm -f "${target:?}" 2>/dev/null || warn "Could not remove ${label} — continuing."
else
skip "${label} not found."
fi
}
# safe_find_delete BASE LABEL [find options…]
# Runs find inside BASE (if it exists) and deletes matches; skips if BASE absent.
safe_find_delete() {
local base="$1" label="$2"; shift 2
if [[ -d "$base" ]]; then
info "Pruning ${label}"
find "$base" "$@" -delete 2>/dev/null || true
else
skip "${label} base directory not found."
fi
}
# clean_dirs LABEL DIR [DIR …]
# Calls safe_rm on each DIR; prints a single success line at the end if any
# directory was found, or a single skip line if none were.
clean_dirs() {
local label="$1"; shift
local found=0
for d in "$@"; do
if [[ -d "$d" ]]; then
safe_rm "$d" "$(basename "$d")"
found=1
else
skip "$(basename "$d") not found."
fi
done
if [[ $found -eq 1 ]]; then
success "${label} cleaned."
else
skip "${label} — nothing to clean."
fi
}
# ── Root check ────────────────────────────────────────────────────────────────
if [[ $EUID -ne 0 ]]; then
warn "Some cleanups require root. Re-running with sudo…"
exec sudo bash "$0" "$@"
fi
echo -e "\n${BOLD}${CYAN}╔══════════════════════════════════════════╗"
echo -e "║ 🧹 Linux System Cleanup ║"
echo -e "╚══════════════════════════════════════════╝${RESET}"
echo -e " Started: $(date '+%Y-%m-%d %H:%M:%S')\n"
TOTAL_BEFORE=$(df / --output=used -BM 2>/dev/null | tail -1 | tr -d 'M' || echo 0)
START_TIME=$(date '+%Y-%m-%d %H:%M:%S')
# Identify the actual human user (not root when sudo'd)
REAL_USER="${SUDO_USER:-${USER:-root}}"
REAL_HOME=$(getent passwd "$REAL_USER" 2>/dev/null | cut -d: -f6 || echo "/root")
# ══════════════════════════════════════════════════════════════════════════════
header "1 · Docker"
# ══════════════════════════════════════════════════════════════════════════════
if has docker && docker info &>/dev/null 2>&1; then
info "Removing stopped containers…"
docker container prune -f 2>/dev/null || warn "docker container prune failed — skipping."
info "Removing dangling images…"
docker image prune -f 2>/dev/null || warn "docker image prune failed — skipping."
info "Removing unused volumes…"
docker volume prune -f 2>/dev/null || warn "docker volume prune failed — skipping."
info "Removing unused networks…"
docker network prune -f 2>/dev/null || warn "docker network prune failed — skipping."
info "Full system prune (unused images, build cache)…"
docker system prune -af --volumes 2>/dev/null || warn "docker system prune failed — skipping."
success "Docker cleaned."
elif has docker; then
skip "Docker installed but daemon is not running."
else
skip "Docker not installed."
fi
# ══════════════════════════════════════════════════════════════════════════════
header "2 · npm"
# ══════════════════════════════════════════════════════════════════════════════
if has npm; then
NPM_CACHE=$(npm config get cache 2>/dev/null || echo "${REAL_HOME}/.npm")
info "npm cache: ${NPM_CACHE} ($(dir_size "$NPM_CACHE"))"
npm cache clean --force 2>/dev/null || warn "npm cache clean failed — skipping."
success "npm cache cleared."
else
skip "npm not installed."
fi
# ══════════════════════════════════════════════════════════════════════════════
header "3 · Yarn"
# ══════════════════════════════════════════════════════════════════════════════
if has yarn; then
YARN_CACHE=$(yarn cache dir 2>/dev/null || echo "${REAL_HOME}/.yarn/cache")
info "Yarn cache: ${YARN_CACHE} ($(dir_size "$YARN_CACHE"))"
yarn cache clean --all 2>/dev/null || yarn cache clean 2>/dev/null || warn "yarn cache clean failed — skipping."
success "Yarn cache cleared."
else
skip "Yarn not installed."
fi
# ══════════════════════════════════════════════════════════════════════════════
header "4 · pnpm"
# ══════════════════════════════════════════════════════════════════════════════
if has pnpm; then
info "Pruning pnpm store…"
pnpm store prune 2>/dev/null || warn "pnpm store prune failed — skipping."
success "pnpm store pruned."
else
skip "pnpm not installed."
fi
# ══════════════════════════════════════════════════════════════════════════════
header "5 · pip / pip3"
# ══════════════════════════════════════════════════════════════════════════════
PIP_CMD=""
has pip3 && PIP_CMD="pip3"
has pip && PIP_CMD="${PIP_CMD:-pip}"
if [[ -n "$PIP_CMD" ]]; then
PIP_CACHE=$($PIP_CMD cache dir 2>/dev/null || echo "${REAL_HOME}/.cache/pip")
info "pip cache: ${PIP_CACHE} ($(dir_size "$PIP_CACHE"))"
$PIP_CMD cache purge 2>/dev/null || safe_rm "$PIP_CACHE" "pip cache"
success "pip cache cleared."
else
skip "pip not installed."
fi
# ══════════════════════════════════════════════════════════════════════════════
header "6 · apt / dpkg"
# ══════════════════════════════════════════════════════════════════════════════
if has apt-get; then
info "apt autoremove…"
apt-get autoremove -y -qq 2>/dev/null || warn "apt autoremove failed — skipping."
info "apt autoclean…"
apt-get autoclean -y -qq 2>/dev/null || warn "apt autoclean failed — skipping."
info "apt clean (package cache)…"
apt-get clean 2>/dev/null || warn "apt clean failed — skipping."
success "apt cleaned."
else
skip "apt not available (not a Debian/Ubuntu system)."
fi
# dnf / yum (Fedora / RHEL)
if has dnf; then
info "dnf autoremove + clean…"
dnf autoremove -y -q 2>/dev/null || warn "dnf autoremove failed — skipping."
dnf clean all -q 2>/dev/null || warn "dnf clean failed — skipping."
success "dnf cleaned."
elif has yum; then
info "yum autoremove + clean…"
yum autoremove -y -q 2>/dev/null || warn "yum autoremove failed — skipping."
yum clean all -q 2>/dev/null || warn "yum clean failed — skipping."
success "yum cleaned."
fi
# ══════════════════════════════════════════════════════════════════════════════
header "7 · systemd journal logs"
# ══════════════════════════════════════════════════════════════════════════════
if has journalctl; then
JOURNAL_SIZE=$(journalctl --disk-usage 2>/dev/null | awk '{print $NF}' | head -1 || echo "unknown")
info "Journal size before: ${JOURNAL_SIZE}"
journalctl --vacuum-time=7d --vacuum-size=100M 2>/dev/null || warn "journalctl vacuum failed — skipping."
success "Journal vacuumed (kept last 7 days / ≤100 MB)."
else
skip "journalctl not found."
fi
# ══════════════════════════════════════════════════════════════════════════════
header "8 · /tmp and /var/tmp"
# ══════════════════════════════════════════════════════════════════════════════
if [[ -d /tmp ]]; then
info "Removing files in /tmp older than 7 days…"
find /tmp -mindepth 1 -maxdepth 2 -atime +7 -delete 2>/dev/null || true
success "/tmp pruned."
else
skip "/tmp not found."
fi
if [[ -d /var/tmp ]]; then
info "Removing files in /var/tmp older than 30 days…"
find /var/tmp -mindepth 1 -maxdepth 2 -atime +30 -delete 2>/dev/null || true
success "/var/tmp pruned."
else
skip "/var/tmp not found."
fi
# ══════════════════════════════════════════════════════════════════════════════
header "9 · User thumbnail & browser caches"
# ══════════════════════════════════════════════════════════════════════════════
safe_rm "${REAL_HOME}/.cache/thumbnails" "thumbnail cache"
for CACHE_DIR in \
"${REAL_HOME}/.cache/google-chrome/Default/Cache" \
"${REAL_HOME}/.cache/mozilla" \
"${REAL_HOME}/.cache/opera" \
"${REAL_HOME}/.cache/BraveSoftware" \
"${REAL_HOME}/.cache/vivaldi" \
"${REAL_HOME}/.local/share/Trash"
do
safe_rm "$CACHE_DIR"
done
# ══════════════════════════════════════════════════════════════════════════════
header "10 · Snap (if installed)"
# ══════════════════════════════════════════════════════════════════════════════
if has snap; then
info "Removing old/disabled snap revisions…"
snap list --all 2>/dev/null \
| awk '/disabled/{print $1, $3}' \
| while read -r snapname revision; do
snap remove "$snapname" --revision="$revision" 2>/dev/null || true
done
success "Old snap revisions removed."
else
skip "snap not installed."
fi
# ══════════════════════════════════════════════════════════════════════════════
header "11 · Flatpak (if installed)"
# ══════════════════════════════════════════════════════════════════════════════
if has flatpak; then
info "Removing unused Flatpak runtimes…"
flatpak uninstall --unused -y 2>/dev/null || warn "flatpak uninstall failed — skipping."
success "Unused Flatpak runtimes removed."
else
skip "flatpak not installed."
fi
# ══════════════════════════════════════════════════════════════════════════════
header "12 · Old kernel images (Debian/Ubuntu only)"
# ══════════════════════════════════════════════════════════════════════════════
if has dpkg && has uname; then
CURRENT_KERNEL=$(uname -r)
info "Running kernel: ${CURRENT_KERNEL}. Running autoremove to drop old kernels…"
apt-get autoremove --purge -y -qq 2>/dev/null || warn "apt autoremove --purge failed — skipping."
success "Old kernels handled by autoremove."
else
skip "dpkg/uname not found — skipping kernel cleanup."
fi
# ══════════════════════════════════════════════════════════════════════════════
header "13 · Core dump files"
# ══════════════════════════════════════════════════════════════════════════════
info "Searching for core dumps…"
CORE_COUNT=$(find / -xdev -maxdepth 6 \( -name 'core' -o -name 'core.[0-9]*' \) 2>/dev/null | wc -l || echo 0)
if [[ "$CORE_COUNT" -gt 0 ]]; then
find / -xdev -maxdepth 6 \( -name 'core' -o -name 'core.[0-9]*' \) -delete 2>/dev/null || true
success "Removed ${CORE_COUNT} core dump file(s)."
else
skip "No core dumps found."
fi
# ══════════════════════════════════════════════════════════════════════════════
header "14 · VS Code"
# ══════════════════════════════════════════════════════════════════════════════
VSCODE_FOUND=0
for D in \
"${REAL_HOME}/.config/Code/Cache" \
"${REAL_HOME}/.config/Code/CachedData" \
"${REAL_HOME}/.config/Code/CachedExtensionVSIXs" \
"${REAL_HOME}/.config/Code/Code Cache" \
"${REAL_HOME}/.config/Code/GPUCache" \
"${REAL_HOME}/.config/Code/Crashpad" \
"${REAL_HOME}/.config/Code/logs" \
"${REAL_HOME}/.config/Code/Backups" \
"${REAL_HOME}/.vscode-server/bin" \
"${REAL_HOME}/.vscode-server/extensionHostProcess"
do
if [[ -d "$D" ]]; then
safe_rm "$D" "VS Code/$(basename "$D")"
VSCODE_FOUND=1
else
skip "VS Code/$(basename "$D") not found."
fi
done
safe_find_delete \
"${REAL_HOME}/.config/Code/User/workspaceStorage" \
"VS Code workspaceStorage (>30 days)" \
-mindepth 1 -maxdepth 1 -type d -atime +30
[[ $VSCODE_FOUND -eq 1 ]] && success "VS Code caches/logs cleared." || skip "VS Code — no data found."
# ══════════════════════════════════════════════════════════════════════════════
header "15 · Cursor (AI code editor)"
# ══════════════════════════════════════════════════════════════════════════════
CURSOR_FOUND=0
for D in \
"${REAL_HOME}/.config/Cursor/Cache" \
"${REAL_HOME}/.config/Cursor/CachedData" \
"${REAL_HOME}/.config/Cursor/CachedExtensionVSIXs" \
"${REAL_HOME}/.config/Cursor/Code Cache" \
"${REAL_HOME}/.config/Cursor/GPUCache" \
"${REAL_HOME}/.config/Cursor/Crashpad" \
"${REAL_HOME}/.config/Cursor/logs" \
"${REAL_HOME}/.config/Cursor/Backups" \
"${REAL_HOME}/.cursor/cache" \
"${REAL_HOME}/.cursor/logs" \
"${REAL_HOME}/.cursor/tmp"
do
if [[ -d "$D" ]]; then
safe_rm "$D" "Cursor/$(basename "$D")"
CURSOR_FOUND=1
else
skip "Cursor/$(basename "$D") not found."
fi
done
safe_find_delete \
"${REAL_HOME}/.config/Cursor/User/workspaceStorage" \
"Cursor workspaceStorage (>30 days)" \
-mindepth 1 -maxdepth 1 -type d -atime +30
[[ $CURSOR_FOUND -eq 1 ]] && success "Cursor caches/logs cleared." || skip "Cursor — no data found."
# ══════════════════════════════════════════════════════════════════════════════
header "16 · OpenAI Codex / Codex CLI"
# ══════════════════════════════════════════════════════════════════════════════
CODEX_FOUND=0
for D in \
"${REAL_HOME}/.codex/cache" \
"${REAL_HOME}/.codex/logs" \
"${REAL_HOME}/.codex/tmp" \
"${REAL_HOME}/.cache/openai"
do
if [[ -d "$D" ]]; then
safe_rm "$D" "Codex/$(basename "$D")"
CODEX_FOUND=1
else
skip "Codex/$(basename "$D") not found."
fi
done
safe_find_delete \
"${REAL_HOME}/.codex/sessions" \
"Codex sessions (>30 days)" \
-type f -atime +30
[[ $CODEX_FOUND -eq 1 ]] && success "Codex caches/logs cleared." || skip "Codex — no data found."
# ══════════════════════════════════════════════════════════════════════════════
header "17 · Claude (Anthropic desktop / CLI)"
# ══════════════════════════════════════════════════════════════════════════════
CLAUDE_FOUND=0
for D in \
"${REAL_HOME}/.config/Claude/Cache" \
"${REAL_HOME}/.config/Claude/Code Cache" \
"${REAL_HOME}/.config/Claude/GPUCache" \
"${REAL_HOME}/.config/Claude/Crashpad" \
"${REAL_HOME}/.config/Claude/logs" \
"${REAL_HOME}/.claude/cache" \
"${REAL_HOME}/.claude/logs" \
"${REAL_HOME}/.claude/tmp" \
"${REAL_HOME}/.cache/claude" \
"${REAL_HOME}/.cache/anthropic"
do
if [[ -d "$D" ]]; then
safe_rm "$D" "Claude/$(basename "$D")"
CLAUDE_FOUND=1
else
skip "Claude/$(basename "$D") not found."
fi
done
for CONV_DIR in \
"${REAL_HOME}/.claude/conversations" \
"${REAL_HOME}/.claude/projects"
do
safe_find_delete "$CONV_DIR" \
"Claude $(basename "$CONV_DIR") logs (>30 days)" \
-type f \( -name '*.jsonl' -o -name '*.json' \) -atime +30
done
[[ $CLAUDE_FOUND -eq 1 ]] && success "Claude caches/logs cleared." || skip "Claude — no data found."
# ══════════════════════════════════════════════════════════════════════════════
# Summary — disk usage report
# ══════════════════════════════════════════════════════════════════════════════
# Capture post-clean stats
TOTAL_AFTER=$(df / --output=used -BM 2>/dev/null | tail -1 | tr -d 'M' || echo 0)
TOTAL_AVAIL=$(df / --output=avail -BM 2>/dev/null | tail -1 | tr -d 'M' || echo 0)
TOTAL_SIZE=$(df / --output=size -BM 2>/dev/null | tail -1 | tr -d 'M' || echo 0)
FREED=$(( TOTAL_BEFORE - TOTAL_AFTER ))
USED_PCT=0
[[ $TOTAL_SIZE -gt 0 ]] && USED_PCT=$(( TOTAL_AFTER * 100 / TOTAL_SIZE ))
FREE_PCT=$(( 100 - USED_PCT ))
# Human-readable helpers (MB → GB when >= 1024)
# Uses only bash integer arithmetic — no awk/bc quoting issues.
fmt_mb() {
local mb="$1"
if [[ $mb -ge 1024 ]]; then
local whole=$(( mb / 1024 ))
local frac=$(( (mb % 1024) * 10 / 1024 ))
echo "${whole}.${frac} GB"
else
echo "${mb} MB"
fi
}
# Build a simple ASCII bar (width = 40 chars)
disk_bar() {
local pct="$1" # 0-100
local width=40
local filled=$(( pct * width / 100 ))
local empty=$(( width - filled ))
local bar=""
local i
for (( i=0; i<filled; i++ )); do bar+=""; done
for (( i=0; i<empty; i++ )); do bar+=""; done
echo "$bar"
}
echo -e "\n${BOLD}${GREEN}╔══════════════════════════════════════════════════════╗"
echo -e "║ 🎉 All done! ║"
echo -e "╚══════════════════════════════════════════════════════╝${RESET}"
echo ""
# ── Timing ────────────────────────────────────────────────────────────────────
echo -e " ${BOLD}Started :${RESET} ${START_TIME}"
echo -e " ${BOLD}Finished :${RESET} $(date '+%Y-%m-%d %H:%M:%S')"
echo ""
# ── Space savings ─────────────────────────────────────────────────────────────
echo -e " ${BOLD}── Disk Space Report ─────────────────────────────────${RESET}"
echo -e " ${BOLD}Before clean :${RESET} $(fmt_mb $TOTAL_BEFORE) used"
echo -e " ${BOLD}After clean :${RESET} $(fmt_mb $TOTAL_AFTER) used"
echo ""
if [[ $FREED -gt 0 ]]; then
echo -e " ${GREEN}${BOLD} ✦ Space freed : $(fmt_mb $FREED)${RESET}"
else
echo -e " ${YELLOW} Space freed : < 1 MB (already clean, or filesystem rounding)${RESET}"
fi
echo ""
# ── Current disk state ────────────────────────────────────────────────────────
BAR=$(disk_bar "$USED_PCT")
# Colour the bar: green <70%, yellow <90%, red ≥90%
if [[ $USED_PCT -ge 90 ]]; then
BAR_COLOR="$RED"
elif [[ $USED_PCT -ge 70 ]]; then
BAR_COLOR="$YELLOW"
else
BAR_COLOR="$GREEN"
fi
echo -e " ${BOLD}── / Partition ───────────────────────────────────────${RESET}"
echo -e " ${BAR_COLOR}${BAR}${RESET} ${USED_PCT}% used"
echo -e " Used : $(fmt_mb $TOTAL_AFTER) of $(fmt_mb $TOTAL_SIZE)"
echo -e " Free : $(fmt_mb $TOTAL_AVAIL)"
echo ""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment