repo-admin.nuss.name · VPN/LAN

Nuss Repository Builder

Skript importieren, reproduzierbar bauen, prüfen und nach ausdrücklicher Freigabe in apt.nuss.name veröffentlichen.

1. Eingangsordner

/home/nussname/web/repo-admin.nuss.name/private/builder/incoming

sysinfo.sh

2. Projekte bauen

nuss-sysinfo

Version 2.2.0 all

Kompakte Systemübersicht für Linux-Systeme

3. Vorschau und Veröffentlichung

PUBLISH succeeded nuss-sysinfo 2.2.0
BUILD succeeded nuss-sysinfo 2.2.0
Build-ID
7185a9d0bff1ef6097338ee59cd6afe1
Quelltext
6d1acaf31b510545bbe579f35d300b915b397cc27cd324333a8bfeb1df24a26d
DEB
eb9c945c9d67d666b497606267d0680e2d7631a3980a5a01e69b6858086a1e7c
Gebauten Quelltext prüfen
#!/usr/bin/env bash

# ==============================================================================
# sysinfo.sh - Kompakte Systemübersicht für Linux-Systeme
#
# Autor:   Daniel Nuß
# Version: 2.2.0
# ==============================================================================

set -o pipefail

readonly SCRIPT_VERSION="2.2.0"
readonly EXTERNAL_IP_URL="https://api.ipify.org"
readonly WEATHER_URL="https://wttr.in/Hochheim%20am%20Main?format=%t,+%C&lang=de"
readonly BASHRC_BLOCK_BEGIN="# >>> sysinfo.sh - automatisch verwaltet >>>"
readonly BASHRC_BLOCK_END="# <<< sysinfo.sh - automatisch verwaltet <<<"

show_help() {
    cat <<EOF
Verwendung: ${0##*/} [OPTION]

Zeigt eine kompakte Übersicht des lokalen Linux-Systems an.
Ohne Option werden die Systeminformationen ausgegeben.

Optionen:
      --install    Abhängigkeiten installieren und in ~/.bashrc aktivieren
      --uninstall  Automatischen Aufruf aus ~/.bashrc entfernen
      --check      Benötigte und optionale Kommandos prüfen
  -h, --help       Diese Hilfe anzeigen
  -V, --version    Skriptversion anzeigen
EOF
}

get_script_path() {
    local script_path="${BASH_SOURCE[0]}"

    if [[ "$script_path" != /* ]]; then
        script_path="$(pwd)/$script_path"
    fi

    if command -v readlink >/dev/null 2>&1; then
        readlink -f -- "$script_path" 2>/dev/null || printf '%s' "$script_path"
    else
        printf '%s' "$script_path"
    fi
}

get_bashrc_path() {
    local account_directory="${HOME:-}"
    local bashrc_path=""

    if [[ -z "$account_directory" ]]; then
        printf 'FEHLER: Das Benutzerverzeichnis konnte nicht ermittelt werden.\n' >&2
        return 1
    fi

    bashrc_path="${account_directory}/.bashrc"

    # Bei einer vorhandenen Verknüpfung den Inhalt der Zieldatei bearbeiten,
    # statt die Verknüpfung beim atomaren Austausch zu ersetzen.
    if [[ -e "$bashrc_path" ]] && command -v readlink >/dev/null 2>&1; then
        readlink -f -- "$bashrc_path" 2>/dev/null || printf '%s' "$bashrc_path"
    else
        printf '%s' "$bashrc_path"
    fi
}

print_command_check() {
    local command_name="$1"

    if command -v "$command_name" >/dev/null 2>&1; then
        printf '  [OK]     %s\n' "$command_name"
        return 0
    fi

    printf '  [FEHLT]  %s\n' "$command_name"
    return 1
}

check_dependencies() {
    local command_name
    local missing_required=0
    local bashrc_path=""
    local -a required_commands=(
        apt apt-get awk chmod date df env grep ip mktemp mv readlink rm sed tr uname
    )

    printf '%s %s - Abhängigkeitsprüfung\n' "${0##*/}" "$SCRIPT_VERSION"
    printf '\nPflichtkommandos:\n'

    if [[ -n "${BASH_VERSION:-}" ]]; then
        printf '  [OK]     bash\n'
    else
        printf '  [FEHLT]  bash\n'
        missing_required=1
    fi

    for command_name in "${required_commands[@]}"; do
        if ! print_command_check "$command_name"; then
            missing_required=1
        fi
    done

    if command -v curl >/dev/null 2>&1; then
        printf '  [OK]     HTTPS-Client: curl\n'
    elif command -v wget >/dev/null 2>&1; then
        printf '  [OK]     HTTPS-Client: wget\n'
    else
        printf '  [FEHLT]  HTTPS-Client: curl oder wget\n'
        missing_required=1
    fi

    if [[ -r /etc/ssl/certs/ca-certificates.crt ]]; then
        printf '  [OK]     CA-Zertifikate\n'
    else
        printf '  [FEHLT]  CA-Zertifikate\n'
        missing_required=1
    fi

    printf '\nOptionale Erweiterungen:\n'
    for command_name in pydf tput vcgencmd; do
        if command -v "$command_name" >/dev/null 2>&1; then
            printf '  [OK]     %s\n' "$command_name"
        else
            printf '  [OPTION] %s nicht installiert\n' "$command_name"
        fi
    done

    bashrc_path=$(get_bashrc_path 2>/dev/null || true)
    printf '\nAnmeldeintegration:\n'
    if [[ -n "$bashrc_path" && -r "$bashrc_path" ]] && \
       grep -Fqx "$BASHRC_BLOCK_BEGIN" "$bashrc_path" 2>/dev/null; then
        printf '  [AKTIV]  %s\n' "$bashrc_path"
    else
        printf '  [INAKTIV] sysinfo.sh ist nicht in ~/.bashrc eingetragen\n'
    fi

    printf '\n'
    if (( missing_required == 0 )); then
        printf 'Ergebnis: Alle Pflichtkommandos sind vorhanden.\n'
        return 0
    fi

    printf 'Ergebnis: Mindestens ein Pflichtkommando fehlt.\n'
    return 1
}

collect_missing_apt_packages() {
    local coreutils_missing=0
    local command_name
    local -a packages=()

    command -v apt >/dev/null 2>&1 || packages+=(apt)
    command -v awk >/dev/null 2>&1 || packages+=(mawk)
    command -v grep >/dev/null 2>&1 || packages+=(grep)
    command -v ip >/dev/null 2>&1 || packages+=(iproute2)
    command -v sed >/dev/null 2>&1 || packages+=(sed)

    if ! command -v curl >/dev/null 2>&1 && \
       ! command -v wget >/dev/null 2>&1; then
        packages+=(curl)
    fi

    for command_name in chmod date df env mktemp mv readlink rm tr uname; do
        if ! command -v "$command_name" >/dev/null 2>&1; then
            coreutils_missing=1
            break
        fi
    done
    (( coreutils_missing == 0 )) || packages+=(coreutils)

    [[ -r /etc/ssl/certs/ca-certificates.crt ]] || packages+=(ca-certificates)

    if (( ${#packages[@]} > 0 )); then
        printf '%s\n' "${packages[@]}"
    fi
}

run_apt_get() {
    if ! command -v apt-get >/dev/null 2>&1; then
        printf 'FEHLER: apt-get ist nicht vorhanden; automatische Installation nicht möglich.\n' >&2
        return 1
    fi

    if (( EUID == 0 )); then
        DEBIAN_FRONTEND=noninteractive apt-get "$@"
    elif command -v sudo >/dev/null 2>&1; then
        sudo env DEBIAN_FRONTEND=noninteractive apt-get "$@"
    else
        printf 'FEHLER: Für die Paketinstallation werden root-Rechte oder sudo benötigt.\n' >&2
        return 1
    fi
}

install_dependencies() {
    local -a packages=()

    if ! command -v apt-get >/dev/null 2>&1; then
        printf 'FEHLER: --install benötigt ein Debian-/Ubuntu-System mit apt-get.\n' >&2
        return 1
    fi

    mapfile -t packages < <(collect_missing_apt_packages)

    if (( ${#packages[@]} == 0 )); then
        printf 'Alle benötigten APT-Pakete sind bereits vorhanden.\n'
        return 0
    fi

    printf 'Fehlende Pakete: %s\n' "${packages[*]}"
    printf 'APT-Paketlisten werden aktualisiert ...\n'
    run_apt_get update || return 1

    printf 'Fehlende Pakete werden installiert ...\n'
    run_apt_get install -y --no-install-recommends "${packages[@]}" || return 1
}

rewrite_bashrc_without_managed_block() {
    local bashrc_path="$1"
    local temporary_file=""

    temporary_file=$(mktemp "${bashrc_path}.sysinfo.XXXXXX") || return 1

    if ! awk \
        -v begin_marker="$BASHRC_BLOCK_BEGIN" \
        -v end_marker="$BASHRC_BLOCK_END" '
            $0 == begin_marker {
                if (line_count > 0 && lines[line_count] ~ /^[[:space:]]*$/) {
                    delete lines[line_count]
                    line_count--
                }
                managed_block = 1
                next
            }
            $0 == end_marker {
                managed_block = 0
                next
            }
            !managed_block {
                lines[++line_count] = $0
            }
            END {
                for (line_number = 1; line_number <= line_count; line_number++) {
                    print lines[line_number]
                }
            }
        ' "$bashrc_path" > "$temporary_file"; then
        rm -f -- "$temporary_file"
        return 1
    fi

    chmod --reference="$bashrc_path" "$temporary_file" 2>/dev/null || \
        chmod 0644 "$temporary_file"

    if ! mv -f -- "$temporary_file" "$bashrc_path"; then
        rm -f -- "$temporary_file"
        return 1
    fi
}

install_bashrc_integration() {
    local bashrc_path=""
    local script_path=""
    local bash_path=""
    local quoted_script_path=""
    local quoted_bash_path=""

    bashrc_path=$(get_bashrc_path) || return 1
    script_path=$(get_script_path) || return 1
    bash_path=$(command -v bash) || return 1

    if [[ ! -r "$script_path" ]]; then
        printf 'FEHLER: Das Skript ist nicht lesbar: %s\n' "$script_path" >&2
        return 1
    fi

    if [[ ! -e "$bashrc_path" ]]; then
        : > "$bashrc_path" || return 1
        chmod 0644 "$bashrc_path" || return 1
    fi

    rewrite_bashrc_without_managed_block "$bashrc_path" || {
        printf 'FEHLER: %s konnte nicht vorbereitet werden.\n' "$bashrc_path" >&2
        return 1
    }

    printf -v quoted_script_path '%q' "$script_path"
    printf -v quoted_bash_path '%q' "$bash_path"

    {
        printf '\n%s\n' "$BASHRC_BLOCK_BEGIN"
        printf 'if [[ $- == *i* ]] && [[ -r %s ]]; then\n' "$quoted_script_path"
        printf '    %s %s\n' "$quoted_bash_path" "$quoted_script_path"
        printf 'fi\n'
        printf '%s\n' "$BASHRC_BLOCK_END"
    } >> "$bashrc_path"

    printf 'Installiert: sysinfo.sh wird bei neuen interaktiven Bash-Sitzungen ausgeführt.\n'
    printf 'Eintrag: %s\n' "$bashrc_path"
    printf 'Skript:  %s\n' "$script_path"
}

uninstall_bashrc_integration() {
    local bashrc_path=""

    bashrc_path=$(get_bashrc_path) || return 1

    if [[ ! -e "$bashrc_path" ]] || \
       ! grep -Fqx "$BASHRC_BLOCK_BEGIN" "$bashrc_path" 2>/dev/null; then
        printf 'Kein verwalteter sysinfo.sh-Eintrag in %s gefunden.\n' "$bashrc_path"
        return 0
    fi

    rewrite_bashrc_without_managed_block "$bashrc_path" || {
        printf 'FEHLER: Der Eintrag konnte nicht aus %s entfernt werden.\n' "$bashrc_path" >&2
        return 1
    }

    printf 'Entfernt: sysinfo.sh wird nicht mehr automatisch über %s gestartet.\n' \
        "$bashrc_path"
}

if (( $# > 1 )); then
    printf 'FEHLER: Es darf nur eine Option angegeben werden.\n\n' >&2
    show_help >&2
    exit 2
fi

case "${1:-}" in
    "")
        ;;
    --install|—install|–install)
        install_dependencies || exit 1
        if ! check_dependencies >/dev/null; then
            check_dependencies
            exit 1
        fi
        install_bashrc_integration || exit 1
        check_dependencies
        exit $?
        ;;
    --uninstall|—uninstall|–uninstall)
        uninstall_bashrc_integration
        exit $?
        ;;
    --check|—check|–check)
        check_dependencies
        exit $?
        ;;
    -h|--help|—help|–help)
        show_help
        exit 0
        ;;
    -V|--version|—version|–version)
        printf '%s %s\n' "${0##*/}" "$SCRIPT_VERSION"
        exit 0
        ;;
    *)
        printf 'Unbekannte Option: %s\n\n' "$1" >&2
        show_help >&2
        exit 2
        ;;
esac

# Farben nur verwenden, wenn die Ausgabe tatsächlich an ein Terminal geht.
color_green=""
color_red=""
color_white_bg=""
color_reset=""

if [[ -t 1 && -n "${TERM:-}" ]] && command -v tput >/dev/null 2>&1; then
    color_green=$(tput setaf 2 2>/dev/null || true)
    color_red=$(tput setaf 1 2>/dev/null || true)
    color_white_bg=$(tput setab 7 2>/dev/null || true)
    color_reset=$(tput sgr0 2>/dev/null || true)
fi

print_banner_line() {
    local text="${1:-}"
    local width=59
    local text_length=${#text}
    local left_padding=0
    local right_padding=0

    if (( text_length < width )); then
        left_padding=$(( (width - text_length) / 2 ))
        right_padding=$(( width - text_length - left_padding ))
    fi

    printf '%s%s%*s%s%*s%s\n' \
        "$color_red" "$color_white_bg" \
        "$left_padding" "" "$text" "$right_padding" "" \
        "$color_reset"
}

print_banner() {
    local line_number

    for ((line_number = 0; line_number < 5; line_number++)); do
        print_banner_line
    done

    print_banner_line "Daniel Nuß & Marcus Heße-Nuß"
    print_banner_line "Am Bittelborn 23A"
    print_banner_line "65239 Hochheim am Main"

    for ((line_number = 0; line_number < 5; line_number++)); do
        print_banner_line
    done
}

get_uptime() {
    local uptime_raw="0"
    local uptime_seconds=0
    local days=0
    local hours=0
    local minutes=0
    local seconds=0

    if [[ -r /proc/uptime ]]; then
        read -r uptime_raw _ < /proc/uptime
        uptime_seconds=${uptime_raw%%.*}
    fi

    [[ "$uptime_seconds" =~ ^[0-9]+$ ]] || uptime_seconds=0

    seconds=$((uptime_seconds % 60))
    minutes=$((uptime_seconds / 60 % 60))
    hours=$((uptime_seconds / 3600 % 24))
    days=$((uptime_seconds / 86400))

    printf '%d Tage, %02dh%02dm%02ds' "$days" "$hours" "$minutes" "$seconds"
}

get_device_model() {
    local model_file

    for model_file in \
        /proc/device-tree/model \
        /sys/firmware/devicetree/base/model; do
        if [[ -f "$model_file" && -r "$model_file" ]]; then
            tr -d '\0' < "$model_file"
            return 0
        fi
    done

    return 1
}

get_cpu_temperature() {
    local temperature=""
    local raw_temperature=""
    local sensor_file

    if command -v vcgencmd >/dev/null 2>&1; then
        temperature=$(vcgencmd measure_temp 2>/dev/null || true)
        if [[ "$temperature" =~ ([0-9]+([.][0-9]+)?) ]]; then
            printf '%s°C' "${BASH_REMATCH[1]}"
            return 0
        fi
    fi

    for sensor_file in /sys/class/thermal/thermal_zone*/temp; do
        [[ -r "$sensor_file" ]] || continue
        read -r raw_temperature < "$sensor_file"

        if [[ "$raw_temperature" =~ ^[0-9]+$ ]] && \
           (( raw_temperature > 0 && raw_temperature < 200000 )); then
            awk -v value="$raw_temperature" 'BEGIN { printf "%.1f°C", value / 1000 }'
            return 0
        fi
    done

    return 1
}

get_memory_value() {
    local field="$1"
    awk -v field="$field" '$1 == field ":" { print $2; exit }' /proc/meminfo 2>/dev/null
}

get_process_count() {
    local process_directory
    local process_count=0

    for process_directory in /proc/[0-9]*; do
        [[ -d "$process_directory" ]] || continue
        ((process_count += 1))
    done

    printf '%d' "$process_count"
}

print_ipv4_addresses() {
    local interface_name
    local address
    local found=0

    if command -v ip >/dev/null 2>&1; then
        while read -r interface_name address; do
            [[ -n "$interface_name" && -n "$address" ]] || continue
            interface_name=${interface_name%%@*}
            address=${address%%/*}
            printf 'IPv4 %-16s: %s\n' "$interface_name" "$address"
            found=1
        done < <(ip -o -4 address show scope global 2>/dev/null | awk '{ print $2, $4 }')
    fi

    if (( found == 0 )); then
        printf 'IPv4................: nicht ermittelbar\n'
    fi
}

fetch_https() {
    local url="$1"

    if command -v curl >/dev/null 2>&1; then
        curl --ipv4 --fail --silent --show-error \
            --connect-timeout 3 --max-time 5 "$url" 2>/dev/null
    elif command -v wget >/dev/null 2>&1; then
        wget --inet4-only --quiet --output-document=- \
            --timeout=5 --tries=1 "$url" 2>/dev/null
    else
        return 127
    fi
}

get_external_ip() {
    local external_ip=""

    external_ip=$(fetch_https "$EXTERNAL_IP_URL" | tr -d '\r\n' || true)

    if [[ -n "$external_ip" ]]; then
        printf '%s' "$external_ip"
    else
        printf 'nicht ermittelbar'
    fi
}

get_weather() {
    local weather=""

    weather=$(fetch_https "$WEATHER_URL" | tr -d '\r\n' || true)

    if [[ -n "$weather" ]]; then
        printf '%s' "$weather"
    else
        printf 'nicht ermittelbar'
    fi
}

get_apt_update_status() {
    local apt_output=""
    local update_count=0

    if ! command -v apt >/dev/null 2>&1; then
        printf 'nicht geprüft (APT nicht installiert)'
        return 0
    fi

    # Absichtlich kein "apt update": Der Schnellcheck verwendet ausschließlich
    # die bereits lokal vorhandenen Paketlisten und verändert das System nicht.
    if ! apt_output=$(LC_ALL=C apt list --upgradable 2>/dev/null); then
        printf 'Prüfung fehlgeschlagen (APT)'
        return 0
    fi

    update_count=$(awk 'NR > 1 && NF > 0 { count++ } END { print count + 0 }' \
        <<< "$apt_output")

    if (( update_count > 0 )); then
        printf 'JA - %d APT-Update(s) verfügbar (lokale Paketlisten)' "$update_count"
    else
        printf 'NEIN - laut lokalen APT-Paketlisten'
    fi
}

print_disk_space() {
    if command -v pydf >/dev/null 2>&1; then
        pydf
    else
        df -hT
    fi
}

uptime_text=$(get_uptime)
device_model=$(get_device_model || true)
cpu_temperature=$(get_cpu_temperature || true)
memory_total_kb=$(get_memory_value MemTotal)
memory_available_kb=$(get_memory_value MemAvailable)
load_one="-"
load_five="-"
load_fifteen="-"

if [[ -r /proc/loadavg ]]; then
    read -r load_one load_five load_fifteen _ < /proc/loadavg
fi

# MemAvailable existiert seit Linux 3.14. Auf sehr alten Systemen zurückfallen.
if [[ -z "$memory_available_kb" ]]; then
    memory_available_kb=$(get_memory_value MemFree)
fi

print_banner

printf '%s%s\n' "$color_green" "$(date '+%A, %e. %B %Y, %T')"
printf '%s\n' "$(uname -srmo)"
printf '%s' "$color_red"

printf 'Uptime...............: %s\n' "$uptime_text"

if [[ -n "$device_model" ]]; then
    printf 'Gerätetyp............: %s\n' "$device_model"
fi

printf 'Speicher verfügbar...: %s kB / %s kB gesamt\n' \
    "${memory_available_kb:-unbekannt}" "${memory_total_kb:-unbekannt}"

if [[ -n "$cpu_temperature" ]]; then
    printf 'CPU-Temperatur.......: %s\n' "$cpu_temperature"
fi

printf 'Last (Durchschnitt)..: %s, %s, %s (1, 5, 15 min)\n' \
    "$load_one" "$load_five" "$load_fifteen"
printf 'Laufende Prozesse....: %s\n' "$(get_process_count)"

print_ipv4_addresses

printf 'IP-Adresse extern....: %s\n' "$(get_external_ip)"
printf 'Hochheim a.M. Wetter.: %s\n' "$(get_weather)"
printf 'Freier Speicherplatz.:\n'
print_disk_space

# Gewünschte letzte sichtbare Ausgabezeile.
printf 'Paket-Updates........: %s\n' "$(get_apt_update_status)"

printf '%s' "$color_reset"

.deb herunterladen veröffentlicht
PUBLISH succeeded nuss-sysinfo 2.2.0
BUILD succeeded nuss-sysinfo 2.2.0
Build-ID
4a5eeac4057acd2c122508655379b461
Quelltext
6d1acaf31b510545bbe579f35d300b915b397cc27cd324333a8bfeb1df24a26d
DEB
eb9c945c9d67d666b497606267d0680e2d7631a3980a5a01e69b6858086a1e7c
Gebauten Quelltext prüfen
#!/usr/bin/env bash

# ==============================================================================
# sysinfo.sh - Kompakte Systemübersicht für Linux-Systeme
#
# Autor:   Daniel Nuß
# Version: 2.2.0
# ==============================================================================

set -o pipefail

readonly SCRIPT_VERSION="2.2.0"
readonly EXTERNAL_IP_URL="https://api.ipify.org"
readonly WEATHER_URL="https://wttr.in/Hochheim%20am%20Main?format=%t,+%C&lang=de"
readonly BASHRC_BLOCK_BEGIN="# >>> sysinfo.sh - automatisch verwaltet >>>"
readonly BASHRC_BLOCK_END="# <<< sysinfo.sh - automatisch verwaltet <<<"

show_help() {
    cat <<EOF
Verwendung: ${0##*/} [OPTION]

Zeigt eine kompakte Übersicht des lokalen Linux-Systems an.
Ohne Option werden die Systeminformationen ausgegeben.

Optionen:
      --install    Abhängigkeiten installieren und in ~/.bashrc aktivieren
      --uninstall  Automatischen Aufruf aus ~/.bashrc entfernen
      --check      Benötigte und optionale Kommandos prüfen
  -h, --help       Diese Hilfe anzeigen
  -V, --version    Skriptversion anzeigen
EOF
}

get_script_path() {
    local script_path="${BASH_SOURCE[0]}"

    if [[ "$script_path" != /* ]]; then
        script_path="$(pwd)/$script_path"
    fi

    if command -v readlink >/dev/null 2>&1; then
        readlink -f -- "$script_path" 2>/dev/null || printf '%s' "$script_path"
    else
        printf '%s' "$script_path"
    fi
}

get_bashrc_path() {
    local account_directory="${HOME:-}"
    local bashrc_path=""

    if [[ -z "$account_directory" ]]; then
        printf 'FEHLER: Das Benutzerverzeichnis konnte nicht ermittelt werden.\n' >&2
        return 1
    fi

    bashrc_path="${account_directory}/.bashrc"

    # Bei einer vorhandenen Verknüpfung den Inhalt der Zieldatei bearbeiten,
    # statt die Verknüpfung beim atomaren Austausch zu ersetzen.
    if [[ -e "$bashrc_path" ]] && command -v readlink >/dev/null 2>&1; then
        readlink -f -- "$bashrc_path" 2>/dev/null || printf '%s' "$bashrc_path"
    else
        printf '%s' "$bashrc_path"
    fi
}

print_command_check() {
    local command_name="$1"

    if command -v "$command_name" >/dev/null 2>&1; then
        printf '  [OK]     %s\n' "$command_name"
        return 0
    fi

    printf '  [FEHLT]  %s\n' "$command_name"
    return 1
}

check_dependencies() {
    local command_name
    local missing_required=0
    local bashrc_path=""
    local -a required_commands=(
        apt apt-get awk chmod date df env grep ip mktemp mv readlink rm sed tr uname
    )

    printf '%s %s - Abhängigkeitsprüfung\n' "${0##*/}" "$SCRIPT_VERSION"
    printf '\nPflichtkommandos:\n'

    if [[ -n "${BASH_VERSION:-}" ]]; then
        printf '  [OK]     bash\n'
    else
        printf '  [FEHLT]  bash\n'
        missing_required=1
    fi

    for command_name in "${required_commands[@]}"; do
        if ! print_command_check "$command_name"; then
            missing_required=1
        fi
    done

    if command -v curl >/dev/null 2>&1; then
        printf '  [OK]     HTTPS-Client: curl\n'
    elif command -v wget >/dev/null 2>&1; then
        printf '  [OK]     HTTPS-Client: wget\n'
    else
        printf '  [FEHLT]  HTTPS-Client: curl oder wget\n'
        missing_required=1
    fi

    if [[ -r /etc/ssl/certs/ca-certificates.crt ]]; then
        printf '  [OK]     CA-Zertifikate\n'
    else
        printf '  [FEHLT]  CA-Zertifikate\n'
        missing_required=1
    fi

    printf '\nOptionale Erweiterungen:\n'
    for command_name in pydf tput vcgencmd; do
        if command -v "$command_name" >/dev/null 2>&1; then
            printf '  [OK]     %s\n' "$command_name"
        else
            printf '  [OPTION] %s nicht installiert\n' "$command_name"
        fi
    done

    bashrc_path=$(get_bashrc_path 2>/dev/null || true)
    printf '\nAnmeldeintegration:\n'
    if [[ -n "$bashrc_path" && -r "$bashrc_path" ]] && \
       grep -Fqx "$BASHRC_BLOCK_BEGIN" "$bashrc_path" 2>/dev/null; then
        printf '  [AKTIV]  %s\n' "$bashrc_path"
    else
        printf '  [INAKTIV] sysinfo.sh ist nicht in ~/.bashrc eingetragen\n'
    fi

    printf '\n'
    if (( missing_required == 0 )); then
        printf 'Ergebnis: Alle Pflichtkommandos sind vorhanden.\n'
        return 0
    fi

    printf 'Ergebnis: Mindestens ein Pflichtkommando fehlt.\n'
    return 1
}

collect_missing_apt_packages() {
    local coreutils_missing=0
    local command_name
    local -a packages=()

    command -v apt >/dev/null 2>&1 || packages+=(apt)
    command -v awk >/dev/null 2>&1 || packages+=(mawk)
    command -v grep >/dev/null 2>&1 || packages+=(grep)
    command -v ip >/dev/null 2>&1 || packages+=(iproute2)
    command -v sed >/dev/null 2>&1 || packages+=(sed)

    if ! command -v curl >/dev/null 2>&1 && \
       ! command -v wget >/dev/null 2>&1; then
        packages+=(curl)
    fi

    for command_name in chmod date df env mktemp mv readlink rm tr uname; do
        if ! command -v "$command_name" >/dev/null 2>&1; then
            coreutils_missing=1
            break
        fi
    done
    (( coreutils_missing == 0 )) || packages+=(coreutils)

    [[ -r /etc/ssl/certs/ca-certificates.crt ]] || packages+=(ca-certificates)

    if (( ${#packages[@]} > 0 )); then
        printf '%s\n' "${packages[@]}"
    fi
}

run_apt_get() {
    if ! command -v apt-get >/dev/null 2>&1; then
        printf 'FEHLER: apt-get ist nicht vorhanden; automatische Installation nicht möglich.\n' >&2
        return 1
    fi

    if (( EUID == 0 )); then
        DEBIAN_FRONTEND=noninteractive apt-get "$@"
    elif command -v sudo >/dev/null 2>&1; then
        sudo env DEBIAN_FRONTEND=noninteractive apt-get "$@"
    else
        printf 'FEHLER: Für die Paketinstallation werden root-Rechte oder sudo benötigt.\n' >&2
        return 1
    fi
}

install_dependencies() {
    local -a packages=()

    if ! command -v apt-get >/dev/null 2>&1; then
        printf 'FEHLER: --install benötigt ein Debian-/Ubuntu-System mit apt-get.\n' >&2
        return 1
    fi

    mapfile -t packages < <(collect_missing_apt_packages)

    if (( ${#packages[@]} == 0 )); then
        printf 'Alle benötigten APT-Pakete sind bereits vorhanden.\n'
        return 0
    fi

    printf 'Fehlende Pakete: %s\n' "${packages[*]}"
    printf 'APT-Paketlisten werden aktualisiert ...\n'
    run_apt_get update || return 1

    printf 'Fehlende Pakete werden installiert ...\n'
    run_apt_get install -y --no-install-recommends "${packages[@]}" || return 1
}

rewrite_bashrc_without_managed_block() {
    local bashrc_path="$1"
    local temporary_file=""

    temporary_file=$(mktemp "${bashrc_path}.sysinfo.XXXXXX") || return 1

    if ! awk \
        -v begin_marker="$BASHRC_BLOCK_BEGIN" \
        -v end_marker="$BASHRC_BLOCK_END" '
            $0 == begin_marker {
                if (line_count > 0 && lines[line_count] ~ /^[[:space:]]*$/) {
                    delete lines[line_count]
                    line_count--
                }
                managed_block = 1
                next
            }
            $0 == end_marker {
                managed_block = 0
                next
            }
            !managed_block {
                lines[++line_count] = $0
            }
            END {
                for (line_number = 1; line_number <= line_count; line_number++) {
                    print lines[line_number]
                }
            }
        ' "$bashrc_path" > "$temporary_file"; then
        rm -f -- "$temporary_file"
        return 1
    fi

    chmod --reference="$bashrc_path" "$temporary_file" 2>/dev/null || \
        chmod 0644 "$temporary_file"

    if ! mv -f -- "$temporary_file" "$bashrc_path"; then
        rm -f -- "$temporary_file"
        return 1
    fi
}

install_bashrc_integration() {
    local bashrc_path=""
    local script_path=""
    local bash_path=""
    local quoted_script_path=""
    local quoted_bash_path=""

    bashrc_path=$(get_bashrc_path) || return 1
    script_path=$(get_script_path) || return 1
    bash_path=$(command -v bash) || return 1

    if [[ ! -r "$script_path" ]]; then
        printf 'FEHLER: Das Skript ist nicht lesbar: %s\n' "$script_path" >&2
        return 1
    fi

    if [[ ! -e "$bashrc_path" ]]; then
        : > "$bashrc_path" || return 1
        chmod 0644 "$bashrc_path" || return 1
    fi

    rewrite_bashrc_without_managed_block "$bashrc_path" || {
        printf 'FEHLER: %s konnte nicht vorbereitet werden.\n' "$bashrc_path" >&2
        return 1
    }

    printf -v quoted_script_path '%q' "$script_path"
    printf -v quoted_bash_path '%q' "$bash_path"

    {
        printf '\n%s\n' "$BASHRC_BLOCK_BEGIN"
        printf 'if [[ $- == *i* ]] && [[ -r %s ]]; then\n' "$quoted_script_path"
        printf '    %s %s\n' "$quoted_bash_path" "$quoted_script_path"
        printf 'fi\n'
        printf '%s\n' "$BASHRC_BLOCK_END"
    } >> "$bashrc_path"

    printf 'Installiert: sysinfo.sh wird bei neuen interaktiven Bash-Sitzungen ausgeführt.\n'
    printf 'Eintrag: %s\n' "$bashrc_path"
    printf 'Skript:  %s\n' "$script_path"
}

uninstall_bashrc_integration() {
    local bashrc_path=""

    bashrc_path=$(get_bashrc_path) || return 1

    if [[ ! -e "$bashrc_path" ]] || \
       ! grep -Fqx "$BASHRC_BLOCK_BEGIN" "$bashrc_path" 2>/dev/null; then
        printf 'Kein verwalteter sysinfo.sh-Eintrag in %s gefunden.\n' "$bashrc_path"
        return 0
    fi

    rewrite_bashrc_without_managed_block "$bashrc_path" || {
        printf 'FEHLER: Der Eintrag konnte nicht aus %s entfernt werden.\n' "$bashrc_path" >&2
        return 1
    }

    printf 'Entfernt: sysinfo.sh wird nicht mehr automatisch über %s gestartet.\n' \
        "$bashrc_path"
}

if (( $# > 1 )); then
    printf 'FEHLER: Es darf nur eine Option angegeben werden.\n\n' >&2
    show_help >&2
    exit 2
fi

case "${1:-}" in
    "")
        ;;
    --install|—install|–install)
        install_dependencies || exit 1
        if ! check_dependencies >/dev/null; then
            check_dependencies
            exit 1
        fi
        install_bashrc_integration || exit 1
        check_dependencies
        exit $?
        ;;
    --uninstall|—uninstall|–uninstall)
        uninstall_bashrc_integration
        exit $?
        ;;
    --check|—check|–check)
        check_dependencies
        exit $?
        ;;
    -h|--help|—help|–help)
        show_help
        exit 0
        ;;
    -V|--version|—version|–version)
        printf '%s %s\n' "${0##*/}" "$SCRIPT_VERSION"
        exit 0
        ;;
    *)
        printf 'Unbekannte Option: %s\n\n' "$1" >&2
        show_help >&2
        exit 2
        ;;
esac

# Farben nur verwenden, wenn die Ausgabe tatsächlich an ein Terminal geht.
color_green=""
color_red=""
color_white_bg=""
color_reset=""

if [[ -t 1 && -n "${TERM:-}" ]] && command -v tput >/dev/null 2>&1; then
    color_green=$(tput setaf 2 2>/dev/null || true)
    color_red=$(tput setaf 1 2>/dev/null || true)
    color_white_bg=$(tput setab 7 2>/dev/null || true)
    color_reset=$(tput sgr0 2>/dev/null || true)
fi

print_banner_line() {
    local text="${1:-}"
    local width=59
    local text_length=${#text}
    local left_padding=0
    local right_padding=0

    if (( text_length < width )); then
        left_padding=$(( (width - text_length) / 2 ))
        right_padding=$(( width - text_length - left_padding ))
    fi

    printf '%s%s%*s%s%*s%s\n' \
        "$color_red" "$color_white_bg" \
        "$left_padding" "" "$text" "$right_padding" "" \
        "$color_reset"
}

print_banner() {
    local line_number

    for ((line_number = 0; line_number < 5; line_number++)); do
        print_banner_line
    done

    print_banner_line "Daniel Nuß & Marcus Heße-Nuß"
    print_banner_line "Am Bittelborn 23A"
    print_banner_line "65239 Hochheim am Main"

    for ((line_number = 0; line_number < 5; line_number++)); do
        print_banner_line
    done
}

get_uptime() {
    local uptime_raw="0"
    local uptime_seconds=0
    local days=0
    local hours=0
    local minutes=0
    local seconds=0

    if [[ -r /proc/uptime ]]; then
        read -r uptime_raw _ < /proc/uptime
        uptime_seconds=${uptime_raw%%.*}
    fi

    [[ "$uptime_seconds" =~ ^[0-9]+$ ]] || uptime_seconds=0

    seconds=$((uptime_seconds % 60))
    minutes=$((uptime_seconds / 60 % 60))
    hours=$((uptime_seconds / 3600 % 24))
    days=$((uptime_seconds / 86400))

    printf '%d Tage, %02dh%02dm%02ds' "$days" "$hours" "$minutes" "$seconds"
}

get_device_model() {
    local model_file

    for model_file in \
        /proc/device-tree/model \
        /sys/firmware/devicetree/base/model; do
        if [[ -f "$model_file" && -r "$model_file" ]]; then
            tr -d '\0' < "$model_file"
            return 0
        fi
    done

    return 1
}

get_cpu_temperature() {
    local temperature=""
    local raw_temperature=""
    local sensor_file

    if command -v vcgencmd >/dev/null 2>&1; then
        temperature=$(vcgencmd measure_temp 2>/dev/null || true)
        if [[ "$temperature" =~ ([0-9]+([.][0-9]+)?) ]]; then
            printf '%s°C' "${BASH_REMATCH[1]}"
            return 0
        fi
    fi

    for sensor_file in /sys/class/thermal/thermal_zone*/temp; do
        [[ -r "$sensor_file" ]] || continue
        read -r raw_temperature < "$sensor_file"

        if [[ "$raw_temperature" =~ ^[0-9]+$ ]] && \
           (( raw_temperature > 0 && raw_temperature < 200000 )); then
            awk -v value="$raw_temperature" 'BEGIN { printf "%.1f°C", value / 1000 }'
            return 0
        fi
    done

    return 1
}

get_memory_value() {
    local field="$1"
    awk -v field="$field" '$1 == field ":" { print $2; exit }' /proc/meminfo 2>/dev/null
}

get_process_count() {
    local process_directory
    local process_count=0

    for process_directory in /proc/[0-9]*; do
        [[ -d "$process_directory" ]] || continue
        ((process_count += 1))
    done

    printf '%d' "$process_count"
}

print_ipv4_addresses() {
    local interface_name
    local address
    local found=0

    if command -v ip >/dev/null 2>&1; then
        while read -r interface_name address; do
            [[ -n "$interface_name" && -n "$address" ]] || continue
            interface_name=${interface_name%%@*}
            address=${address%%/*}
            printf 'IPv4 %-16s: %s\n' "$interface_name" "$address"
            found=1
        done < <(ip -o -4 address show scope global 2>/dev/null | awk '{ print $2, $4 }')
    fi

    if (( found == 0 )); then
        printf 'IPv4................: nicht ermittelbar\n'
    fi
}

fetch_https() {
    local url="$1"

    if command -v curl >/dev/null 2>&1; then
        curl --ipv4 --fail --silent --show-error \
            --connect-timeout 3 --max-time 5 "$url" 2>/dev/null
    elif command -v wget >/dev/null 2>&1; then
        wget --inet4-only --quiet --output-document=- \
            --timeout=5 --tries=1 "$url" 2>/dev/null
    else
        return 127
    fi
}

get_external_ip() {
    local external_ip=""

    external_ip=$(fetch_https "$EXTERNAL_IP_URL" | tr -d '\r\n' || true)

    if [[ -n "$external_ip" ]]; then
        printf '%s' "$external_ip"
    else
        printf 'nicht ermittelbar'
    fi
}

get_weather() {
    local weather=""

    weather=$(fetch_https "$WEATHER_URL" | tr -d '\r\n' || true)

    if [[ -n "$weather" ]]; then
        printf '%s' "$weather"
    else
        printf 'nicht ermittelbar'
    fi
}

get_apt_update_status() {
    local apt_output=""
    local update_count=0

    if ! command -v apt >/dev/null 2>&1; then
        printf 'nicht geprüft (APT nicht installiert)'
        return 0
    fi

    # Absichtlich kein "apt update": Der Schnellcheck verwendet ausschließlich
    # die bereits lokal vorhandenen Paketlisten und verändert das System nicht.
    if ! apt_output=$(LC_ALL=C apt list --upgradable 2>/dev/null); then
        printf 'Prüfung fehlgeschlagen (APT)'
        return 0
    fi

    update_count=$(awk 'NR > 1 && NF > 0 { count++ } END { print count + 0 }' \
        <<< "$apt_output")

    if (( update_count > 0 )); then
        printf 'JA - %d APT-Update(s) verfügbar (lokale Paketlisten)' "$update_count"
    else
        printf 'NEIN - laut lokalen APT-Paketlisten'
    fi
}

print_disk_space() {
    if command -v pydf >/dev/null 2>&1; then
        pydf
    else
        df -hT
    fi
}

uptime_text=$(get_uptime)
device_model=$(get_device_model || true)
cpu_temperature=$(get_cpu_temperature || true)
memory_total_kb=$(get_memory_value MemTotal)
memory_available_kb=$(get_memory_value MemAvailable)
load_one="-"
load_five="-"
load_fifteen="-"

if [[ -r /proc/loadavg ]]; then
    read -r load_one load_five load_fifteen _ < /proc/loadavg
fi

# MemAvailable existiert seit Linux 3.14. Auf sehr alten Systemen zurückfallen.
if [[ -z "$memory_available_kb" ]]; then
    memory_available_kb=$(get_memory_value MemFree)
fi

print_banner

printf '%s%s\n' "$color_green" "$(date '+%A, %e. %B %Y, %T')"
printf '%s\n' "$(uname -srmo)"
printf '%s' "$color_red"

printf 'Uptime...............: %s\n' "$uptime_text"

if [[ -n "$device_model" ]]; then
    printf 'Gerätetyp............: %s\n' "$device_model"
fi

printf 'Speicher verfügbar...: %s kB / %s kB gesamt\n' \
    "${memory_available_kb:-unbekannt}" "${memory_total_kb:-unbekannt}"

if [[ -n "$cpu_temperature" ]]; then
    printf 'CPU-Temperatur.......: %s\n' "$cpu_temperature"
fi

printf 'Last (Durchschnitt)..: %s, %s, %s (1, 5, 15 min)\n' \
    "$load_one" "$load_five" "$load_fifteen"
printf 'Laufende Prozesse....: %s\n' "$(get_process_count)"

print_ipv4_addresses

printf 'IP-Adresse extern....: %s\n' "$(get_external_ip)"
printf 'Hochheim a.M. Wetter.: %s\n' "$(get_weather)"
printf 'Freier Speicherplatz.:\n'
print_disk_space

# Gewünschte letzte sichtbare Ausgabezeile.
printf 'Paket-Updates........: %s\n' "$(get_apt_update_status)"

printf '%s' "$color_reset"

.deb herunterladen veröffentlicht
PUBLISH succeeded nuss-sysinfo 2.1.0
BUILD succeeded nuss-sysinfo 2.1.0
Build-ID
377f57197177a7260995acde1fb70cb0
Quelltext
05068f02396352ef1849652b4b817d783ceef85ae3deffa22280a2855e478839
DEB
35e764e9030345756aae8866e044eb883941f7565caad95252ddf2150d34e439
Gebauten Quelltext prüfen
#!/usr/bin/env bash

# ==============================================================================
# sysinfo.sh - Kompakte Systemübersicht für Linux-Systeme
#
# Autor:   Daniel Nuß
# Version: 2.1.0
# ==============================================================================

set -o pipefail

readonly SCRIPT_VERSION="2.1.0"
readonly EXTERNAL_IP_URL="https://api.ipify.org"
readonly WEATHER_URL="https://wttr.in/Hochheim%20am%20Main?format=%t,+%C&lang=de"

show_help() {
    cat <<EOF
Verwendung: ${0##*/} [OPTION]

Zeigt eine kompakte Übersicht des lokalen Linux-Systems an.

Optionen:
  -h, --help       Diese Hilfe anzeigen
  -V, --version    Skriptversion anzeigen
EOF
}

case "${1:-}" in
    "")
        ;;
    -h|--help)
        show_help
        exit 0
        ;;
    -V|--version)
        printf '%s %s\n' "${0##*/}" "$SCRIPT_VERSION"
        exit 0
        ;;
    *)
        printf 'Unbekannte Option: %s\n\n' "$1" >&2
        show_help >&2
        exit 2
        ;;
esac

# Farben nur verwenden, wenn die Ausgabe tatsächlich an ein Terminal geht.
color_green=""
color_red=""
color_white_bg=""
color_reset=""

if [[ -t 1 && -n "${TERM:-}" ]] && command -v tput >/dev/null 2>&1; then
    color_green=$(tput setaf 2 2>/dev/null || true)
    color_red=$(tput setaf 1 2>/dev/null || true)
    color_white_bg=$(tput setab 7 2>/dev/null || true)
    color_reset=$(tput sgr0 2>/dev/null || true)
fi

print_banner_line() {
    local text="${1:-}"
    local width=59
    local text_length=${#text}
    local left_padding=0
    local right_padding=0

    if (( text_length < width )); then
        left_padding=$(( (width - text_length) / 2 ))
        right_padding=$(( width - text_length - left_padding ))
    fi

    printf '%s%s%*s%s%*s%s\n' \
        "$color_red" "$color_white_bg" \
        "$left_padding" "" "$text" "$right_padding" "" \
        "$color_reset"
}

print_banner() {
    local line_number

    for ((line_number = 0; line_number < 5; line_number++)); do
        print_banner_line
    done

    print_banner_line "Daniel Nuß & Marcus Heße-Nuß"
    print_banner_line "Am Bittelborn 23A"
    print_banner_line "65239 Hochheim am Main"

    for ((line_number = 0; line_number < 5; line_number++)); do
        print_banner_line
    done
}

get_uptime() {
    local uptime_raw="0"
    local uptime_seconds=0
    local days=0
    local hours=0
    local minutes=0
    local seconds=0

    if [[ -r /proc/uptime ]]; then
        read -r uptime_raw _ < /proc/uptime
        uptime_seconds=${uptime_raw%%.*}
    fi

    [[ "$uptime_seconds" =~ ^[0-9]+$ ]] || uptime_seconds=0

    seconds=$((uptime_seconds % 60))
    minutes=$((uptime_seconds / 60 % 60))
    hours=$((uptime_seconds / 3600 % 24))
    days=$((uptime_seconds / 86400))

    printf '%d Tage, %02dh%02dm%02ds' "$days" "$hours" "$minutes" "$seconds"
}

get_device_model() {
    local model_file

    for model_file in \
        /proc/device-tree/model \
        /sys/firmware/devicetree/base/model; do
        if [[ -f "$model_file" && -r "$model_file" ]]; then
            tr -d '\0' < "$model_file"
            return 0
        fi
    done

    return 1
}

get_cpu_temperature() {
    local temperature=""
    local raw_temperature=""
    local sensor_file

    if command -v vcgencmd >/dev/null 2>&1; then
        temperature=$(vcgencmd measure_temp 2>/dev/null || true)
        if [[ "$temperature" =~ ([0-9]+([.][0-9]+)?) ]]; then
            printf '%s°C' "${BASH_REMATCH[1]}"
            return 0
        fi
    fi

    for sensor_file in /sys/class/thermal/thermal_zone*/temp; do
        [[ -r "$sensor_file" ]] || continue
        read -r raw_temperature < "$sensor_file"

        if [[ "$raw_temperature" =~ ^[0-9]+$ ]] && \
           (( raw_temperature > 0 && raw_temperature < 200000 )); then
            awk -v value="$raw_temperature" 'BEGIN { printf "%.1f°C", value / 1000 }'
            return 0
        fi
    done

    return 1
}

get_memory_value() {
    local field="$1"
    awk -v field="$field" '$1 == field ":" { print $2; exit }' /proc/meminfo 2>/dev/null
}

get_process_count() {
    local process_directory
    local process_count=0

    for process_directory in /proc/[0-9]*; do
        [[ -d "$process_directory" ]] || continue
        ((process_count += 1))
    done

    printf '%d' "$process_count"
}

print_ipv4_addresses() {
    local interface_name
    local address
    local found=0

    if command -v ip >/dev/null 2>&1; then
        while read -r interface_name address; do
            [[ -n "$interface_name" && -n "$address" ]] || continue
            interface_name=${interface_name%%@*}
            address=${address%%/*}
            printf 'IPv4 %-16s: %s\n' "$interface_name" "$address"
            found=1
        done < <(ip -o -4 address show scope global 2>/dev/null | awk '{ print $2, $4 }')
    fi

    if (( found == 0 )); then
        printf 'IPv4................: nicht ermittelbar\n'
    fi
}

fetch_https() {
    local url="$1"

    if command -v curl >/dev/null 2>&1; then
        curl --ipv4 --fail --silent --show-error \
            --connect-timeout 3 --max-time 5 "$url" 2>/dev/null
    elif command -v wget >/dev/null 2>&1; then
        wget --inet4-only --quiet --output-document=- \
            --timeout=5 --tries=1 "$url" 2>/dev/null
    else
        return 127
    fi
}

get_external_ip() {
    local external_ip=""

    external_ip=$(fetch_https "$EXTERNAL_IP_URL" | tr -d '\r\n' || true)

    if [[ -n "$external_ip" ]]; then
        printf '%s' "$external_ip"
    else
        printf 'nicht ermittelbar'
    fi
}

get_weather() {
    local weather=""

    weather=$(fetch_https "$WEATHER_URL" | tr -d '\r\n' || true)

    if [[ -n "$weather" ]]; then
        printf '%s' "$weather"
    else
        printf 'nicht ermittelbar'
    fi
}

get_apt_update_status() {
    local apt_output=""
    local update_count=0

    if ! command -v apt >/dev/null 2>&1; then
        printf 'nicht geprüft (APT nicht installiert)'
        return 0
    fi

    # Absichtlich kein "apt update": Der Schnellcheck verwendet ausschließlich
    # die bereits lokal vorhandenen Paketlisten und verändert das System nicht.
    if ! apt_output=$(LC_ALL=C apt list --upgradable 2>/dev/null); then
        printf 'Prüfung fehlgeschlagen (APT)'
        return 0
    fi

    update_count=$(awk 'NR > 1 && NF > 0 { count++ } END { print count + 0 }' \
        <<< "$apt_output")

    if (( update_count > 0 )); then
        printf 'JA - %d APT-Update(s) verfügbar (lokale Paketlisten)' "$update_count"
    else
        printf 'NEIN - laut lokalen APT-Paketlisten'
    fi
}

print_disk_space() {
    if command -v pydf >/dev/null 2>&1; then
        pydf
    else
        df -hT
    fi
}

uptime_text=$(get_uptime)
device_model=$(get_device_model || true)
cpu_temperature=$(get_cpu_temperature || true)
memory_total_kb=$(get_memory_value MemTotal)
memory_available_kb=$(get_memory_value MemAvailable)
load_one="-"
load_five="-"
load_fifteen="-"

if [[ -r /proc/loadavg ]]; then
    read -r load_one load_five load_fifteen _ < /proc/loadavg
fi

# MemAvailable existiert seit Linux 3.14. Auf sehr alten Systemen zurückfallen.
if [[ -z "$memory_available_kb" ]]; then
    memory_available_kb=$(get_memory_value MemFree)
fi

print_banner

printf '%s%s\n' "$color_green" "$(date '+%A, %e. %B %Y, %T')"
printf '%s\n' "$(uname -srmo)"
printf '%s' "$color_red"

printf 'Uptime...............: %s\n' "$uptime_text"

if [[ -n "$device_model" ]]; then
    printf 'Gerätetyp............: %s\n' "$device_model"
fi

printf 'Speicher verfügbar...: %s kB / %s kB gesamt\n' \
    "${memory_available_kb:-unbekannt}" "${memory_total_kb:-unbekannt}"

if [[ -n "$cpu_temperature" ]]; then
    printf 'CPU-Temperatur.......: %s\n' "$cpu_temperature"
fi

printf 'Last (Durchschnitt)..: %s, %s, %s (1, 5, 15 min)\n' \
    "$load_one" "$load_five" "$load_fifteen"
printf 'Laufende Prozesse....: %s\n' "$(get_process_count)"

print_ipv4_addresses

printf 'IP-Adresse extern....: %s\n' "$(get_external_ip)"
printf 'Hochheim a.M. Wetter.: %s\n' "$(get_weather)"
printf 'Freier Speicherplatz.:\n'
print_disk_space

# Gewünschte letzte sichtbare Ausgabezeile.
printf 'Paket-Updates........: %s\n' "$(get_apt_update_status)"

printf '%s' "$color_reset"
.deb herunterladen veröffentlicht