144 lines
3.9 KiB
Bash
144 lines
3.9 KiB
Bash
#!/usr/bin/env bash
|
|
# clean-system — безопасная интерактивная очистка системы
|
|
|
|
set -euo pipefail
|
|
|
|
_size() {
|
|
du -sh "$1" 2>/dev/null | cut -f1 || echo "0"
|
|
}
|
|
|
|
_freed() {
|
|
local before=$1 after=$2
|
|
# оба в байтах через numfmt
|
|
local b a
|
|
b=$(numfmt --from=iec "$before" 2>/dev/null || echo 0)
|
|
a=$(numfmt --from=iec "$after" 2>/dev/null || echo 0)
|
|
local diff=$(( b - a ))
|
|
(( diff > 0 )) && numfmt --to=iec "$diff" || echo "0"
|
|
}
|
|
|
|
# ── Задачи очистки ───────────────────────────────────────────
|
|
# Формат: "id|описание|команда|путь_для_размера"
|
|
|
|
declare -A TASK_CMD TASK_PATH TASK_DESC
|
|
|
|
_register() {
|
|
local id=$1 desc=$2 path=$3; shift 3
|
|
TASK_DESC[$id]="$desc"
|
|
TASK_PATH[$id]="$path"
|
|
TASK_CMD[$id]="$*"
|
|
}
|
|
|
|
_register pacman-cache \
|
|
"Pacman кеш (оставить 2 версии)" \
|
|
"/var/cache/pacman/pkg" \
|
|
sudo paccache -rk2
|
|
|
|
_register paru-cache \
|
|
"Paru build кеш" \
|
|
"$HOME/.cache/paru" \
|
|
paru -Sc --noconfirm
|
|
|
|
_register uv-cache \
|
|
"uv (Python) кеш" \
|
|
"$HOME/.cache/uv" \
|
|
uv cache clean
|
|
|
|
_register npm-cache \
|
|
"npm кеш" \
|
|
"$HOME/.npm" \
|
|
npm cache clean --force
|
|
|
|
_register cargo-cache \
|
|
"Cargo registry (скачанные крейты)" \
|
|
"$HOME/.cargo/registry" \
|
|
rm -rf "$HOME/.cargo/registry/cache" "$HOME/.cargo/registry/src"
|
|
|
|
_register restic-cache \
|
|
"Restic старые кеши" \
|
|
"$HOME/.cache/restic" \
|
|
restic cache --cleanup
|
|
|
|
_register thumbnails \
|
|
"Кеш миниатюр" \
|
|
"$HOME/.cache/thumbnails" \
|
|
rm -rf "$HOME/.cache/thumbnails"
|
|
|
|
_register journal \
|
|
"Systemd journal (оставить 2 недели)" \
|
|
"" \
|
|
journalctl --vacuum-time=2weeks
|
|
|
|
_register pip-cache \
|
|
"pip кеш" \
|
|
"$HOME/.cache/pip" \
|
|
pip3 cache purge
|
|
|
|
_register zsh-compdump \
|
|
"Zsh completion cache (пересоздастся автоматически)" \
|
|
"" \
|
|
bash -c 'rm -f "$HOME"/.config/zsh/.zcompdump*'
|
|
|
|
# ── Построение меню ──────────────────────────────────────────
|
|
|
|
main() {
|
|
if ! command -v fzf &>/dev/null; then
|
|
echo "fzf not found"
|
|
exit 1
|
|
fi
|
|
|
|
local ORDERED=(pacman-cache paru-cache uv-cache npm-cache cargo-cache
|
|
restic-cache thumbnails journal pip-cache zsh-compdump)
|
|
|
|
local lines=()
|
|
for id in "${ORDERED[@]}"; do
|
|
local size=""
|
|
local path="${TASK_PATH[$id]}"
|
|
if [[ -n "$path" && ( -d "$path" || -f "$path" ) ]]; then
|
|
size=$(_size "$path")
|
|
else
|
|
size="—"
|
|
fi
|
|
lines+=("$(printf "%-14s %6s %s" "$id" "$size" "${TASK_DESC[$id]}")")
|
|
done
|
|
|
|
local selected
|
|
selected=$(printf '%s\n' "${lines[@]}" | fzf \
|
|
--multi \
|
|
--prompt "clean > " \
|
|
--header "Пробел — выбрать | Enter — запустить | Ctrl-A — выбрать всё" \
|
|
--bind "ctrl-a:select-all" \
|
|
--reverse \
|
|
--height=50%) || exit 0
|
|
|
|
[[ -z "$selected" ]] && exit 0
|
|
|
|
local total_freed=0
|
|
|
|
while IFS= read -r line; do
|
|
local id
|
|
id=$(echo "$line" | awk '{print $1}')
|
|
local path="${TASK_PATH[$id]}"
|
|
|
|
local before=""
|
|
[[ -n "$path" && ( -d "$path" || -f "$path" ) ]] && before=$(_size "$path")
|
|
|
|
echo ""
|
|
echo "▶ ${TASK_DESC[$id]}"
|
|
eval "${TASK_CMD[$id]}" || true
|
|
|
|
if [[ -n "$path" && -n "$before" ]]; then
|
|
local after
|
|
after=$(_size "$path")
|
|
local freed
|
|
freed=$(_freed "$before" "$after")
|
|
echo " → освобождено: $freed"
|
|
fi
|
|
done <<< "$selected"
|
|
|
|
echo ""
|
|
echo "Готово."
|
|
}
|
|
|
|
main "$@"
|