← Alle Scripts

// Bash-Scripts

Arch-Update mit AUR-Aufräumen

Stößt ein System- und AUR-Update an und findet nebenbei verwaiste AUR-only-Pakete, die niemand mehr braucht.

Arch LinuxAURPaketverwaltung
Version1.2.5
Stand2026-07-06
Getestet aufArch Linux x86_64
LizenzMIT
Brauchtbash 5, pacman, ein AUR-Helfer (Standard: yay)
Umfang247 Zeilen · 7.5 KB
SHA256 2c6f60417d45ada6e06f5a7aa4884bcc439528ee35e8499328218f19516907dd Nach 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.

mapfile -t installed_foreign < <(LC_ALL=C pacman -Qqm | sort)
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[@]}")
)

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 "$@"
Anzeige