SHA2562c6f60417d45ada6e06f5a7aa4884bcc439528ee35e8499328218f19516907ddNach dem Download prüfen: echo "2c6f60417d45ada6e06f5a7aa4884bcc439528ee35e8499328218f19516907dd arch-update.sh" | sha256sum -c
Erst lesen, dann laufen lassen. Der vollständige Quelltext steht weiter unten auf dieser Seite. Einen curl … | bash-Einzeiler gibt es hier bewusst nicht.
Nutzung auf eigene Gefahr — keine Haftung für Datenverlust oder Systemschäden. Siehe Nutzungsbedingungen.
Wofür das Script gut ist
Auf Arch-basierten Systemen läuft ein vollständiges Update meist in zwei Schritten: offizielle Repos mit pacman, AUR-Pakete mit einem Helfer wie yay. Dabei sammeln sich mit der Zeit AUR-Pakete an, die als Abhängigkeit installiert wurden und inzwischen niemand mehr braucht. Ohne regelmäßigen Blick darauf bleiben sie einfach liegen.
Was es macht
Aktualisiert System- und AUR-Pakete über einen AUR-Helfer (Standard: yay).
Findet installierte Pakete, die nicht aus offiziellen Repos stammen (vermutlich AUR).
Trennt sie in „wird noch gebraucht" und „hängt an nichts mehr" (Required By: None).
Bietet an, die unbenötigten zu entfernen.
Prüft bei den noch benötigten AUR-Paketen, ob sie überhaupt noch auffindbar sind
(AUR oder inzwischen in den offiziellen Repos) — und warnt, wenn nicht.
Läuft standardmäßig als Trockenlauf; verändert wird nur mit --apply.
Wie es das umsetzt
Der interessante Teil ist, wie das Script „AUR-only" bestimmt: es vergleicht die Liste der installierten Fremdpakete mit dem, was der AUR-Helfer als bekannte AUR-Pakete führt.
LC_ALL=C ist hier kein Detail, sondern nötig: pacman -Qi gibt Feldnamen wie „Required By" nur auf Englisch konsistent aus. Läuft das System mit einer anderen Sprache eingestellt, würde das Parsen der Abhängigkeiten stillschweigend falsche Ergebnisse liefern — genau die Art Fehler, die man erst bemerkt, wenn schon etwas entfernt wurde, das noch gebraucht wurde.
Warum ich das automatisiert habe
Weil sich AUR-only-Pakete auf Dauer unbemerkt ansammeln und ich sie sonst nur sporadisch von Hand durchgehe.
Aufruf
bash arch-update.sh --help
bash arch-update.sh # Trockenlauf, zeigt nur was passieren würde
bash arch-update.sh --apply # führt Update und Aufräumen wirklich aus
Quelltext
arch-update.sh
#!/usr/bin/env bash
#
# arch-update.sh
# Zweck: System-/AUR-Update anstoßen und verwaiste AUR-only-Pakete finden.
#
# Autor: Matthias Meister — https://scripts.web.mm-core.de
# Version: 1.0.0
#
# Lizenz: MIT — Copyright (c) 2026 Matthias Meister
# Volltext: https://scripts.web.mm-core.de/lizenz/
#
# Exit-Codes:
# 0 = alles gut
# 1 = Problem gefunden (z. B. AUR-Paket nirgends mehr auffindbar)
# 2 = Aufruffehler (falsche Option, Voraussetzung fehlt)
set -euo pipefail
readonly SCRIPT_NAME="${0##*/}"
readonly VERSION="1.0.0"
# ---- Defaults -----------------------------------------------------------
dry_run=1 # Trockenlauf ist Standard, siehe --apply
do_update=1
do_cleanup=1
do_check=1
use_color=1
aur_helper="yay"
exit_code=0
# ---- Ausgabe --------------------------------------------------------------
setup_colors() {
if [[ "$use_color" -eq 1 && -t 1 ]]; then
c_info=$'\033[36m'; c_warn=$'\033[33m'; c_err=$'\033[31m'; c_ok=$'\033[32m'; c_off=$'\033[0m'
else
c_info=""; c_warn=""; c_err=""; c_ok=""; c_off=""
fi
}
info() { printf '%s[Info]%s %s\n' "${c_info}" "${c_off}" "$*"; }
ok() { printf '%s[OK]%s %s\n' "${c_ok}" "${c_off}" "$*"; }
warn() { printf '%s[Warnung]%s %s\n' "${c_warn}" "${c_off}" "$*" >&2; }
err() { printf '%s[Fehler]%s %s\n' "${c_err}" "${c_off}" "$*" >&2; }
usage() {
cat <<EOF
${SCRIPT_NAME} ${VERSION}
System- und AUR-Update anstoßen, dabei verwaiste AUR-only-Pakete finden
und optional entfernen.
Verwendung:
${SCRIPT_NAME} [OPTIONEN]
Optionen:
--apply Änderungen wirklich ausführen (Update, Entfernen).
Ohne diese Option läuft alles nur als Trockenlauf.
--dry-run Nur anzeigen, was passieren würde (Standard).
--no-update System-/AUR-Update überspringen.
--no-cleanup Suche nach verwaisten AUR-only-Paketen überspringen.
--no-check Prüfung noch benötigter AUR-Pakete überspringen.
--aur-helper=PROGRAMM AUR-Helfer verwenden (Standard: yay).
--no-color Ausgabe ohne Farbcodes (z. B. für Cron/Logs).
-h, --help Diese Hilfe anzeigen.
--version Version anzeigen.
Beispiele:
${SCRIPT_NAME} --help
${SCRIPT_NAME} # zeigt nur, was passieren würde
${SCRIPT_NAME} --apply # führt Update und Aufräumen wirklich aus
${SCRIPT_NAME} --apply --no-update # nur aufräumen, kein Systemupdate
${SCRIPT_NAME} --aur-helper=paru --apply
Exit-Codes:
0 = alles gut
1 = Problem gefunden (z. B. AUR-Paket nirgends mehr auffindbar)
2 = Aufruffehler
EOF
}
# ---- Argumente --------------------------------------------------------
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
--apply) dry_run=0 ;;
--dry-run) dry_run=1 ;;
--no-update) do_update=0 ;;
--no-cleanup) do_cleanup=0 ;;
--no-check) do_check=0 ;;
--aur-helper=*) aur_helper="${1#*=}" ;;
--no-color) use_color=0 ;;
-h|--help) usage; exit 0 ;;
--version) printf '%s %s\n' "$SCRIPT_NAME" "$VERSION"; exit 0 ;;
*)
err "Unbekannte Option: $1"
usage
exit 2
;;
esac
shift
done
}
# ---- Voraussetzungen ----------------------------------------------------
check_prerequisites() {
if ! command -v pacman >/dev/null 2>&1; then
err "pacman wurde nicht gefunden. Dieses Skript ist für Arch-basierte Systeme gedacht."
exit 2
fi
if [[ "$do_update" -eq 1 || "$do_cleanup" -eq 1 || "$do_check" -eq 1 ]]; then
if ! command -v "$aur_helper" >/dev/null 2>&1; then
err "AUR-Helfer '${aur_helper}' wurde nicht gefunden."
err "Installieren oder anderen Helfer mit --aur-helper=PROGRAMM angeben."
exit 2
fi
fi
}
# ---- System-/AUR-Update --------------------------------------------------
do_system_update() {
info "Aktualisiere System- und AUR-Pakete mit '${aur_helper} -Syu' ..."
if [[ "$dry_run" -eq 1 ]]; then
info "Trockenlauf: würde ausführen: ${aur_helper} -Syu"
return 0
fi
"$aur_helper" -Syu
ok "Update abgeschlossen."
}
# ---- Verwaiste AUR-only-Pakete finden ------------------------------------
# Vergleicht installierte "fremde" Pakete (nicht in offiziellen Repos, also
# vermutlich aus dem AUR) mit dem, was der AUR-Helfer als AUR-Paketliste
# kennt. LC_ALL=C erzwingt englische, stabil parsbare pacman-Ausgabe -
# sonst hängt das Parsen von "Required By" von der Systemsprache ab.
find_aur_only_packages() {
local -a installed_foreign aur_known aur_only
mapfile -t installed_foreign < <(LC_ALL=C pacman -Qqm | sort)
if [[ "${#installed_foreign[@]}" -eq 0 ]]; then
info "Keine fremden (nicht-offiziellen) Pakete installiert."
return 0
fi
mapfile -t aur_known < <(LC_ALL=C "$aur_helper" -Slq | sort)
mapfile -t aur_only < <(
comm -23 \
<(printf '%s\n' "${installed_foreign[@]}") \
<(printf '%s\n' "${aur_known[@]}")
)
if [[ "${#aur_only[@]}" -eq 0 ]]; then
info "Keine AUR-only-Pakete gefunden."
return 0
fi
info "AUR-only-Pakete gefunden (${#aur_only[@]}):"
printf ' %s\n' "${aur_only[@]}"
local -a unneeded=() needed=()
local pkg required_by
for pkg in "${aur_only[@]}"; do
required_by=$(LC_ALL=C pacman -Qi "$pkg" | awk -F': ' '/^Required By/ {print $2; exit}')
if [[ "$required_by" == "None" ]]; then
unneeded+=("$pkg")
else
needed+=("$pkg")
fi
done
if [[ "$do_cleanup" -eq 1 ]]; then
cleanup_unneeded "${unneeded[@]}"
fi
if [[ "$do_check" -eq 1 ]]; then
check_needed "${needed[@]}"
fi
}
# ---- Nicht mehr benötigte AUR-Pakete entfernen ---------------------------
cleanup_unneeded() {
local -a unneeded=("$@")
if [[ "${#unneeded[@]}" -eq 0 ]]; then
info "Keine unbenötigten AUR-Pakete (ohne Required By)."
return 0
fi
info "Unbenötigte AUR-Pakete (von nichts abhängig):"
printf ' %s\n' "${unneeded[@]}"
if [[ "$dry_run" -eq 1 ]]; then
info "Trockenlauf: würde entfernen mit: pacman -Rns ${unneeded[*]}"
return 0
fi
# pacman -Rns fragt selbst noch einmal interaktiv nach - das bleibt als
# zweite Sicherheitsstufe zusätzlich zu --apply bestehen.
sudo pacman -Rns "${unneeded[@]}"
ok "Entfernt: ${unneeded[*]}"
}
# ---- Noch benötigte AUR-Pakete prüfen ------------------------------------
check_needed() {
local -a needed=("$@")
if [[ "${#needed[@]}" -eq 0 ]]; then
info "Keine noch benötigten AUR-Pakete zu prüfen."
return 0
fi
info "Noch benötigte AUR-Pakete - Verfügbarkeit prüfen:"
local pkg
for pkg in "${needed[@]}"; do
local found_aur=0 found_repo=0
LC_ALL=C "$aur_helper" -Ss "^${pkg}$" 2>/dev/null | grep -q "^aur/${pkg} " && found_aur=1 || true
LC_ALL=C pacman -Ss "^${pkg}$" 2>/dev/null | grep -q "^extra/${pkg} " && found_repo=1 || true
if [[ "$found_aur" -eq 1 ]]; then
ok " ${pkg}: weiterhin im AUR verfügbar."
elif [[ "$found_repo" -eq 1 ]]; then
ok " ${pkg}: mittlerweile in offiziellen Repos verfügbar."
else
warn " ${pkg}: weder im AUR noch in offiziellen Repos gefunden."
warn " -> GitHub prüfen oder manuell neu bauen."
exit_code=1
fi
done
}
main() {
parse_args "$@"
setup_colors
check_prerequisites
if [[ "$dry_run" -eq 1 ]]; then
info "Trockenlauf aktiv (Standard). Für echte Änderungen: --apply"
fi
if [[ "$do_update" -eq 1 ]]; then
do_system_update
fi
if [[ "$do_cleanup" -eq 1 || "$do_check" -eq 1 ]]; then
find_aur_only_packages
fi
exit "$exit_code"
}
main "$@"