Die 2. Auflage meines Scripting-Buchs ist frisch aus der Druckerei und ab Anfang August im Buchhandel erhältlich. Wie schon die erste Auflage dreht sich alles um die drei Scripting-Sprachen Bash, PowerShell und Python. Für die Neuauflage habe ich das Buch vollständig überarbeitet und aktualisiert. Neu dazugekommen sind unter anderem: Terminal Tuning (»Pimp my Terminal«): Nerd … 📚 Scripting (2. Aufl.) weiterlesen →
Die 2. Auflage meines Scripting-Buchs ist frisch aus der Druckerei und ab Anfang August im Buchhandel erhältlich. Wie schon die erste Auflage dreht sich alles um die drei Scripting-Sprachen Bash, PowerShell und Python. Für die Neuauflage habe ich das Buch vollständig überarbeitet und aktualisiert. Neu dazugekommen sind unter anderem: Terminal Tuning (»Pimp my Terminal«): Nerd Fonts, Prompt Frameworks, moderne CLI-Tools Python-Modulverwaltung mit uv Ein neues Kapitel zum Erstellen und Zeichnen von Diagrammen Ein neues Kapitel zum E-Mail-Versand per Script Ein neues Kapitel zur Nutzung von KI-APIs in eigenen Scripts Viele neue Praxisbeispiele: Claude-Code-Sessions exportieren, Web Scraping mit Playwright, GPS-Tracks aus Fotos extrahieren, WordPress-Bilder nachträglich mit Alt-Beschreibungen versehen usw. Gerade jetzt ist Scripting-Wissen wichtiger denn je. KI-Tools wie Claude, ChatGPT oder Gemini erzeugen auf Zuruf Scripts – und führen sie oft gleich selbst aus. Das funktioniert erstaunlich gut, solange jemand am Ruder sitzt, der den resultierenden Code auch beurteilen kann: Welche Sprache eignet sich für die Aufgabe? Was macht dieses PowerShell-Cmdlet eigentlich? Ist der generierte Bash-Einzeiler sicher, oder löscht er versehentlich das falsche Verzeichnis? Ohne dieses Grundwissen bleibt nur blindes Vertrauen in den KI-Output – und das ist bei Code, der auf Servern oder Produktivsystemen läuft, keine gute Idee. Das Buch vermittelt das Fundament, um Scripts selbst oder mit KI-Hilfe zu erstellen: Crashkurse zu den drei Sprachen, das nötige Handwerkszeug (SSH, Git, VS Code, reguläre Ausdrücke, JSON/XML-Verarbeitung) und zahlreiche Praxisbeispiele aus Backup, Bildverarbeitung, Web Scraping, Datenbank- und Cloud-Administration. Wer diese Grundlagen beherrscht, kann KI-generierte Scripts nicht nur einsetzen, sondern auch verstehen, anpassen und im Zweifel selbst debuggen. Alle Infos zum Buch, eine Leseprobe und die Bestell-Links finden Sie auf der Buchseite.
Gemeinsam mit Rainer Hattenhauer arbeite ich gerade an Agentic AI – Wie Sie die KI für sich arbeiten lassen. Das Buch erscheint voraussichtlich Ende Oktober im Rheinwerk Verlag. Es geht nicht mehr um Chatbots, sondern um KI-Agenten, die selbstständig planen, Werkzeuge nutzen und mehrstufige Aufgaben ausführen – von der Tagesplanung über die E-Mail-Kommunikation bis zu … 📚 Vorankündigung: Agentic AI weiterlesen →
Gemeinsam mit Rainer Hattenhauer arbeite ich gerade an Agentic AI – Wie Sie die KI für sich arbeiten lassen. Das Buch erscheint voraussichtlich Ende Oktober im Rheinwerk Verlag. Es geht nicht mehr um Chatbots, sondern um KI-Agenten, die selbstständig planen, Werkzeuge nutzen und mehrstufige Aufgaben ausführen – von der Tagesplanung über die E-Mail-Kommunikation bis zu Workflows mit Skills, MCP, lokalen Modellen und der Steuerung von Smart-Home-Systemen. Das Buch richtet sich explizit nicht an Leute, die mit KI-Unterstützung programmieren möchten. Dieses Thema habe ich mit Bernd Öggl und Sebastian Springer schon in Coding mit KI abgehandelt. <img decoding="async" src="https://kofler.info/wp-content/uploads/agentic-ai.jpg" alt="Das Bild zeigt das Cover eines IT-Fachbuchs zum Thema Agentic AI. Als Autoren werden Rainer Hattenhauer und Michael Kofler genannt, Verlag: Rheinwerk Computing." width="200" height="278" class="alignnone size-full wp-image-9749" srcset="https://kofler.info/wp-content/uploads/agentic-ai.jpg 1142w, https://kofler.info/wp-content/uploads/agentic-ai-467x650.jpg 467w, https://kofler.info/wp-content/uploads/agentic-ai-690x960.jpg 690w, https://kofler.info/wp-content/uploads/agentic-ai-768x1069.jpg 768w, https://kofler.info/wp-content/uploads/agentic-ai-1103x1536.jpg 1103w" sizes="(max-width: 200px) 100vw, 200px" /> Ein paar persönliche Anmerkungen: Der reine Chat mit einer KI – Frage stellen, Antwort bekommen – gehört für mich schon fast der Vergangenheit an. Natürlich verwende ich Chatbots weiterhin zur Recherche. Aber auf dem Rechner installierte KI-Agenten (sprich: die ChatGPT-App, die Claude-App, aber auch Claude Code, oder unter Linux das Programm Hermes) können viel mehr: Ich erstelle damit komplexe Automatisierungs-Setups, die dann in einem faszinierenden Ausmaß selbstständig laufen. Ich frage also nicht mehr »Wie geht das?«, sondern ich fordere den KI-Agenten auf: »Mach das!« Ganz von alleine geht das natürlich nicht. Ein wenig Arbeit für das Setup, das Einrichten von CLAUDE.md oder AGENTS.md, manchmal die Installation eines Plugins oder MCP-Servers — das gehört dazu. Und das lohnt sich meist nur, wenn es um Aufgaben geht, die sich wiederholen. Mein Aha-Erlebnis war die Korrektur einer Linux-Prüfung, die ich vor einem Monat (fast) vollständig auf KI umgestellt habe. Ich werde demnächst im Blog darüber berichten. Nein, die Korrektur erfolgt NICHT zur Gänze KI-gesteuert, ich muss zum Schluss noch einmal darüberschauen. Aber Claude Code (mein Lieblings-Tool für fast alles) nimmt mir jetzt unglaublich viel öde Arbeit ab. Claude Code verbindet sich via SSH mit einem Dutzend virtueller Maschinen, sieht nach, welche der Aufgabenstellungen dort erledigt sind, und trägt die Ergebnisse in eine ODS-Tabelle ein. Grandios! Oder werfen Sie einen Blick auf https://scripting-buch.netlify.app. Spannend ist weniger der Inhalt, den können Sie auch hier auf kofler.info nachlesen. Spannend ist, dass diese Website ausschließlich aus ein paar Prompts entstanden ist. Ich habe der ChatGPT-App (ehemals Codex, jetzt ChatGPT Work) die Markdown-Dateien zum Buch gegeben, einen Link auf die Buchseite beim Rheinwerk-Verlag, und habe im Prinzip gesagt: »Mach‘ mir eine tolle Website zu diesem Buch.« Ich bin nicht leicht zu verblüffen, aber alleine das zum Scripting-Thema so gut passende Layout ist großartig! Mit meinen eher bescheidenen Layout-Fähigkeiten hätte das viel nüchterner, langweiliger ausgesehen. Beachten Sie die konzentrischen Kreisen hinter dem Cover. Die Idee stammt von Codex nach einer Analyse des Cover-Bilds, die Umsetzung sind wenige Zeilen CSS-Code. Das ist schon ziemlich genial. Hab‘ ich Sie neugierig gemacht? Alle Details – Kapitelübersicht und Bestell-Links – finden Sie auf der Buchseite.
Österreich: Schafft die PV-Förderung einfach ab!
In der Vergangenheit gab es in Österreich eine PV-Förderung (EAG-Investitionszuschuss). Die Anträge waren kompliziert, der Fördertopf innerhalb weniger Minuten erschöpft. Die damalige türkis-grüne Regierung hat diesen Unsinn per 1.1.2024 weitgehend abgestellt und stattdessen die Umsatzsteuer für private PV-Anlagen bis 35 kWp ausgesetzt. Damit entfielen für fast alle privaten PV-Anlagen die lästigen Förderanträge bei der OeMAG. … Österreich: Schafft die PV-Förderung einfach ab! weiterlesen →
In der Vergangenheit gab es in Österreich eine PV-Förderung (EAG-Investitionszuschuss). Die Anträge waren kompliziert, der Fördertopf innerhalb weniger Minuten erschöpft. Die damalige türkis-grüne Regierung hat diesen Unsinn per 1.1.2024 weitgehend abgestellt und stattdessen die Umsatzsteuer für private PV-Anlagen bis 35 kWp ausgesetzt. Damit entfielen für fast alle privaten PV-Anlagen die lästigen Förderanträge bei der OeMAG. Die erlassene USt entsprach ziemlich genau der Förderhöhe. Im Gegenzug sank der irrsinige Verwaltungsaufwand praktisch auf Null. Mit dem Regierungswechsel kam das rasche Ende. In einer der ersten Maßnahmen wurde die ohnedies befristete USt-Aussetzung per 1.4.2025 vorzeitig beendet. Aber ein bisschen »öko« wollte die neue Regierung dann doch sein. Das alte Fördermodell wurde mit all seinen Nachteilen reaktiviert, aber mit einem (noch) bescheidenerem Budget ausgestattet. So bescheiden, dass beim letzten Förder-Call nur Anträge innerhalb der ersten 33 Sekunden angenommen wurden (derstandard.at). Lieber ein ehrlicher Förderstopp als eine Verhöhnung des Volkes PV-Produkte sind in den vergangenen Jahren erheblich billiger geworden. Man kann also volkswirtschaftlich argumentieren, dass eine Förderung nicht mehr notwendig ist. Von diesem Argument lasse ich mich sogar überzeugen. Ein regenerativer Umbau Österreichs genießt ja leider nicht die höchste Priorität der Regierung, um es einmal höflich zu formulieren. Insofern wäre es also vermutlich zweckmäßiger, die ohnedies bescheidenen Mittel zur Förderung regenerativer Heizungen (Wärmepumpen!) zu bündeln und den PV-Sektor ganz dem freien Markt zu überlassen. Aber wenn man zu dieser Erkenntnis gelangt, dann sollte man auch den Mut haben, das auszusprechen. Die Pseudo-PV-Förderung, die wir heute haben, ist eine Verhöhnung des Volkes. In den Genuss einer Förderung kann aktuell nur kommen, wer erstens die Formulare für den Förderantrag praktisch auswendig kennt und alle Daten per Cut&Paste blitzschnell einfügen kann; und wer zweitens Glück hat. Dieses System ist absurd. Es ist mit einer Lotterie zu vergleichen. Dann lieber gar keine Förderung! Das aktuelle System bereitet nur Frust und ist sogar kontraproduktiv, weil geplante PV-Anlagen verschoben werden — in der unsinnigen Hoffnung, vielleicht beim nächsten Förder-Call mehr Glück zu haben. Quellen/Links https://www.bmf.gv.at/themen/steuern/fuer-unternehmen/umsatzsteuer/informationen/steuersatz-fuer-photovoltaikmodule.html https://www.derstandard.at/story/3000000331550/solar-foerderung-in-33-sekunden-weg-wie-der-sparkurs-den-photovoltaik-boom-ausbremst https://www.eag-abwicklungsstelle.at
Für die Neuauflage meines Scripting-Buchs habe ich mich zuletzt mit dem Senden und Empfangen von E-Mails per SMTP und IMAP beschäftigt. Dieser Blog-Beitrag stellt das Standardmodul imaplib vor. Damit können Sie per IMAP Postfächer abrufen und verwalten. Die Anwendung ist ein wenig umständlich, aber dafür können Sie wirklich praktisch alles machen, was das Protokoll IMAP … E-Mails mit Python lesen: imaplib weiterlesen →
Für die Neuauflage meines Scripting-Buchs habe ich mich zuletzt mit dem Senden und Empfangen von E-Mails per SMTP und IMAP beschäftigt. Dieser Blog-Beitrag stellt das Standardmodul imaplib vor. Damit können Sie per IMAP Postfächer abrufen und verwalten. Die Anwendung ist ein wenig umständlich, aber dafür können Sie wirklich praktisch alles machen, was das Protokoll IMAP vorsieht. Kurz erklärt: IMAP und Authentifizierung IMAP (Internet Message Access Protocol) ist das Standardprotokoll zum Abrufen und Verwalten von E-Mails auf einem Mailserver. Die Verbindung erfolgt normalerweise über Port 993 mit SSL/TLS. Im Unterschied zu POP3 verbleiben die Nachrichten auf dem Server und lassen sich in Ordnern organisieren – IMAP eignet sich daher besonders gut für die automatisierte Verarbeitung. Klassische Unix/Linux-Mailserver erlauben die Anmeldung mit Benutzername und Passwort. Bei Google-Konten ist das anders: Gmail erfordert entweder App-Passwörter (16-stellige Codes, die Sie nach Aktivierung der Zwei-Faktor-Authentifizierung unter myaccount.google.com/apppasswords erstellen) oder OAuth2. App-Passwörter sind dabei die einfachere Variante für Scripts. Passwörter sollten nie direkt im Scriptcode stehen. Die Beispiele hier lesen die Zugangsdaten aus Umgebungsvariablen, die wiederum aus einer Datei credentials.env geladen werden: # credentials.env (chmod 600; in .gitignore aufnehmen!) IMAP_HOST=mail.example.com IMAP_USER=username IMAP_PASS=topSecret In Python laden Sie die Datei am einfachsten mit python-dotenv: from dotenv import load_dotenv load_dotenv("credentials.env") Das Modul installieren Sie mit pip install python-dotenv oder – wenn Sie uv verwenden – mit uv add python-dotenv. imaplib: Verbinden, suchen und herunterladen imaplib ist seit Python 2 Bestandteil der Standardbibliothek und deckt den vollständigen IMAP-Befehlssatz ab. Das folgende Beispiel-Script stellt die Verbindung zur Inbox her, lädt die zehn neuesten E-Mails herunter und zeigt die wichtigsten Metadaten tabellarisch an – mit * als Indikator für noch ungelesene Nachrichten: * 13-05 17:53 papa.xxx@xxx... AW: Halbjahresabrechnungen 12-05 20:48 kundenxxx@xxx... Terminanfrage Sendungszustel... 12-05 04:02 info@weltxxx... Japan, Korsika oder Sansibar ... 11-05 20:51 noreply@xxx... OpenAI Dev News: Realtime 2.0... 05-05 18:58 cron@webxxx Invitation updated: iprot dev 04-05 08:28 externexxx@fhxxx... Vertrag bereit zur Abbrechnung imaplib.IMAP4_SSL stellt die Verbindung zum IMAP-Server auf Port 993 her. select öffnet einen Ordner, search liefert eine Liste von Nachrichten-IDs als leerzeichen-getrennte Byte-Zeichenkette, fetch lädt die Rohdaten einer einzelnen oder mehrerer Nachrichten. Der Parameter readonly=True bei select stellt sicher, dass das Abrufen der Nachrichten keine Nebeneffekte hat – insbesondere werden keine Nachrichten als gelesen markiert. Das ist wichtig, weil IMAP-Server den Status einer Nachricht bereits beim Öffnen verändern können. search(None, "ALL") liefert eine aufsteigend sortierte Liste aller Nachrichten-IDs im Postfach. Mit split()[-10:] extrahieren Sie die zehn neuesten. Diese IDs werden, getrennt durch Kommas, zu einem einzigen fetch-Aufruf zusammengefasst. Als Fetch-Attribute übergeben Sie FLAGS für den Lesestatus sowie BODY.PEEK[HEADER.FIELDS (...)], um nur die benötigten Header-Felder abzurufen. PEEK verhindert dabei, dass der Server die Nachrichten automatisch als gelesen kennzeichnet. Jede Zeile der Server-Antwort ist ein Tupel aus Metadaten und rohen Header-Bytes. ParseFlags wertet die Metadaten aus und gibt die IMAP-Flags als Tupel zurück. Wenn \Seen fehlt, gilt die Nachricht als ungelesen. message_from_bytes wandelt die Header-Bytes in ein auswertbares Objekt um. parsedate_to_datetime macht aus einem RFC-2822-Datum ein datetime-Objekt, das dann mit strftime nach eigenen Vorstellungen formatiert werden kann. parseaddr zerlegt das From-Feld in ein (Name, Adresse)-Tupel. MIME-kodierte Header-Zeichenketten wie =?utf-8?q?...?= entschlüsselt decode_header aus dem Modul email.header. Die Ergebnisse werden zunächst in einer Liste gesammelt, da die Reihenfolge der Server-Antwort nicht zwingend der Reihenfolge der angefragten IDs entspricht. reversed dreht die Liste beim Ausgeben um, sodass die neueste Nachricht zuerst erscheint. # Beispieldatei fetch-imap.py import os, email, imaplib from email.header import decode_header, make_header from email.utils import parsedate_to_datetime, parseaddr from dotenv import load_dotenv # IMAP-Konfigurationsparameter lesen load_dotenv("credentials.env") HOST = os.environ["IMAP_HOST"] USER = os.environ["IMAP_USER"] PASS = os.environ["IMAP_PASS"] # RFC-2047-Header (=?utf-8?q?...?=) dekodieren def decode_mime(value: str | None) -> str: return str(make_header(decode_header(value or ""))) # Zeichenkette auf max_len verkürzen def truncate(text: str, n: int) -> str: return text if len(text) <= n else text[: n - 3] + "..." # Verbindung zum IMAP-Server with imaplib.IMAP4_SSL(HOST) as imap: imap.login(USER, PASS) imap.select("INBOX", readonly=True) # nichts ändern! # IDs aller Nachrichten ermitteln -> Byte-String für fetch() _, data = imap.search(None, "ALL") id_set = b",".join(data[0].split()[-10:]) # max. 10 # IDs der ungelesenen Nachrichten _, unseen_data = imap.search(None, "UNSEEN") unseen = set(unseen_data[0].split()) # relevante Spalten abfragen (IMAP-Syntax); PEEK, damit # das Seen-Flag nicht gesetzt wird fields = "(FLAGS BODY.PEEK[HEADER.FIELDS (DATE FROM SUBJECT)])" _, rows = imap.fetch(id_set, fields) # Daten/Spalten dekodieren und formatieren messages = [] for row in rows: if not isinstance(row, tuple): continue meta, raw_headers = row # Sequence-Nummer am Beginn der Metadaten (b'4 (FLAGS ...') seq = meta.split()[0] is_new = seq in unseen msg = email.message_from_bytes(raw_headers) dt = parsedate_to_datetime(msg["Date"]) date = dt.strftime("%d-%m %H:%M") addr = parseaddr(decode_mime(msg.get("From", "")))[1] sender = truncate(addr, 20) raw_sub = decode_mime(msg.get("Subject", "(no subject)")) subject = truncate(raw_sub, 40) messages.append((is_new, date, sender, subject)) # in umgekehrter Reihenfolge ausgeben, die neueste Mail zuerst for is_new, date, sender, subject in reversed(messages): flag = "*" if is_new else " " print(f"{flag} {date} {sender:<20} {subject}") Was imaplib sonst noch kann Das obige Beispiel kratzt nur an der Oberfläche. imaplib deckt den vollständigen IMAP-Befehlssatz ab: Vollständige Nachrichten laden: Mit fetch können Sie nicht nur Header, sondern auch den kompletten Nachrichtentext inklusive Anhänge abrufen. Filtern: search akzeptiert IMAP-Suchkriterien wie FROM, SUBJECT, SINCE oder UNSEEN, um gezielt nach bestimmten Nachrichten zu suchen. Flags setzen: store setzt oder entfernt Flags wie \Seen, \Flagged oder \Deleted. Löschen: expunge löscht die als \Deleted markierten Nachrichten endgültig. Ordner verwalten: copy verschiebt Nachrichten zwischen Ordnern, list gibt alle verfügbaren Mailboxen zurück, create und delete legen neue Ordner an oder entfernen sie. Kurz gesagt: Von der einfachen Posteingangsübersicht bis zur vollautomatisierten Mailbox-Verwaltung ist alles drin. Alternativen zu imaplib Wer die etwas sperrige API von imaplib als mühsam empfindet, kann auf IMAPClient ausweichen. Die Bibliothek ist ein High-Level-Wrapper um imaplib, der insbesondere den Umgang mit Nachrichten-IDs, Flags und Ordnern deutlich angenehmer macht. Das folgende Mini-Beispiel zeigt die Verbindung und das Abrufen der Betreffzeilen aller ungelesenen Nachrichten: from imapclient import IMAPClient with IMAPClient(HOST) as client: client.login(USER, PASS) client.select_folder("INBOX", readonly=True) messages = client.search("UNSEEN") for uid, data in client.fetch(messages, "ENVELOPE").items(): print(data[b"ENVELOPE"].subject.decode()) IMAPClient installieren Sie mit pip install imapclient bzw. uv add imapclient. Wer IMAP in einem asyncio-Kontext benötigt, greift zu aioimaplib – einer vollständig async-fähigen Bibliothek, da imaplib synchron blockiert. Und imbox ist eine sehr einsteigerfreundliche Abstraktion, die E-Mails als Python-Objekte mit direkt zugänglichen Attributen wie .subject oder .attachments liefert. Der Nachteil: weniger Kontrolle bei komplexen Operationen. Quellen und Links imaplib – Dokumentation (docs.python.org) Introduction to IMAP (nickb.dev) python-dotenv IMAPClient aioimaplib imbox
Mitte Juni 2026 wurden über 1500 AUR-Pakete kompromittiert (siehe auch den vorigen Blog-Beitrag zu diesem Thema). Es zeugt natürlich von großer Überheblichkeit, als Mitautor eines Hacking-Buches zu glauben, selbst immun gegen Angriffe zu sein. Ein Update zum falschen Zeitpunkt hat mich auf den Boden der Tatsachen zurückgeholt und mir — einen Tag vor Urlaubsantritt — … Lehren aus dem AUR-Angriff weiterlesen →
Mitte Juni 2026 wurden über 1500 AUR-Pakete kompromittiert (siehe auch den vorigen Blog-Beitrag zu diesem Thema). Es zeugt natürlich von großer Überheblichkeit, als Mitautor eines Hacking-Buches zu glauben, selbst immun gegen Angriffe zu sein. Ein Update zum falschen Zeitpunkt hat mich auf den Boden der Tatsachen zurückgeholt und mir — einen Tag vor Urlaubsantritt — eine Menge sinnloser Arbeit beschert. Ich habe Anthropic- und OpenAI-Keys widerrufen, die SSH-Keys des betroffenen Notebooks von diversen Servern und Dienstleistern gelöscht und unzählige Passwörter geändert. Sch***! Heute habe ich, natürlich ohne das System neuerlich zu booten, eine Analyse gemacht. Im Prinzip: pacman --root /mnt/arch --dbpath /mnt/arch/var/lib/pacman -Qm Ich habe 60 AUR-Pakete gefunden. Nur eines davon (libgdata, eine veraltete GNOME-Bibliothek für den Zugriff auf Google-Dienste) wurde kompromittiert. Ich habe es nur Stunden nach der Manipulation, aber eben noch vor der Berichterstattung über den Hack installiert. Extremes Pech im Timing! Dieser Blog-Beitrag ist der Versuch einer persönlichen Aufarbeitung. Was ist passiert? Warum ist es passiert? Und was kann ich daraus lernen? Eines vorweg. Dieser Artikel ist keine Kritik am Arch-Linux-Projekt. Dieses hat immer klar kommuniziert, dass AUR-Pakete — wie der Name schon sagt (Arch User Repository) — von den Benutzern selbst gepflegt werden und keiner Kontrolle unterliegen. Wer solche Pakete installiert, ist selbst verantwortlich, mit allen — dieses Mal sehr unerfreulichen — Konsequenzen. Auch Updates können gefährlich sein Die Sicherheitsempfehlung schlechthin lautet: »Installieren Sie regelmäßig Updates.« Aber diese Regel gilt nur für Pakete aus offiziellen Quellen. Für extern gepflegte Pakete wäre eine Cool-Down-Phase sinnvoll. Im Prinzip: »Mach ein Update aller offiziellen Pakete sowie eines aller extern gepflegten Pakete, sofern dieses Update zumindest 4 Tage alt ist«. (Über die genaue Zeitspanne kann man streiten.) Ich kenne allerdings keinen Paketmanager, der so eine Funktion bietet. In die richtige Richtung gehen die Auto-Update-Funktionen von Debian und Ubuntu: Unter Debian werden per Default ausschließlich offizielle Debian-Sicherheitsupdates berücksichtigt (Datei /etc/apt/apt.conf.d/50unattended-upgrades). Sonstige Updates werden ignoriert und müssen manuell installiert werden. Ubuntu ist etwas liberaler und installiert alle Updates aus offiziellen Quellen (aber ebenfalls keine aus externen Quellen). Kurz gesagt: Ein blindes Update über alle Pakete ist nur sinnvoll, wenn Sie sich über die Herkunft aller Pakete sicher sind. Vielleicht werde ich in zukünftigen Blog-Artikeln Tipps zusammenfassen, wie Updates feiner gesteuert werden können. Wozu überhaupt nicht-offizielle Pakete? Eine andere Sicherheitsempfehlung lautet: »Verwenden Sie nur offiziell gepflegte Pakete.« Dennoch hat praktisch jede Distribution zusätzliche Paketquellen: Arch Linux: AUR Debian: externe Debian-Repositories Fedora: externe YUM-Paketquellen, COPR RHEL + Klone: EPEL, Remi und andere externe YUM-Paketquellen Ubuntu: externe Debian-Repositories, PPAs Wenn externe Quellen unsicher sind, warum gibt es sie dann überhaupt? Weil sie manchmal der einzige und viel öfter der bequemste Weg sind, um Software zu installieren, die in den offiziellen Quellen fehlt. Für mich als Autor ist es wichtig, neue, nicht so bekannte Programme unkompliziert auszuprobieren. Viele Entwickler nutzen externe Pakete zur Installation von Tools, die nicht oder nur in veralteten Versionen zur Verfügung stehen. Schließlich fehlen kostenlose Programme mit kommerziellem Ursprung (also keine reine Open-Source-Software) wie Google Chrome in den offiziellen Quellen. Für »große« Distributionen gibt es zumeist »halb-offizielle« Pakete, aber für kleinere Distributionen wie Arch Linux sind Sie auf AUR-Pakete angewiesen. Insofern ist der Rat, auf externe Quellen zu verzichten, für fortgeschrittene Benutzer und Software-Entwicklerinnen nur schwer umzusetzen. Alles, worüber ich hier im Kontext von Linux-Paketen schreibe, gilt im Übrigen auch für die Erweiterungen/Bibliotheken aller wichtigen Programmiersprachen, Editoren und anderer Tools: also für Python-Module, NPM-Pakete, VSCode-Plugins etc. Der Überbegriff für Angriffe auf derartige Zusatzpakete lautet Software Supply Chain Attack (Lieferkettenangriff). Weniger ist mehr Für mich persönlich ist das AUR-Debakel ein Grund, die Nutzung externer Pakete viel stärker zu hinterfragen. Vorgenommen habe ich mir folgende Regeln: So wenig externe Pakete wie möglich! (Gibt es geeignete Alternativen in den offiziellen Quellen?) Ungenutzte externe Pakete deinstallieren. (Welche Pakete habe ich zwei, drei Monate nicht mehr gebraucht? Weg damit!) Eine stärkere Differenzierung zwischen Test- und Work-Systemen. Schadensminimierung Der AUR-Angriff hat auf Authentifizierungsdaten abgezielt, also Keys, Tokens, Passwörter etc. aus allen erdenklichen Quellen (.ssh-Verzeichnis, Passwörter diverser Browser usw.) Eine sehr detaillierte Analyse der Malware finden Sie auf ioctl.fail. In meinem Fall war das größte Problem die Passwortsynchronisation von Google Chrome. Ich speichere im Webbrowser viele Passwörter. Die Passwort-Synchronisation ist durch ein zusätzliches, persönliches Passwort geschützt. Bookmarks und Passwörter sollten also für Google unlesbar sein. Wenn ich ein neues System einrichte (Linux, Windows, macOS, iOS oder Android), installiere ich Google Chrome, melde mich bei Google an, gebe das Master-Passwort für Bookmarks und Passwörter ein und synchronisiere die Daten. Das geht blitzschnell und ist komfortabel. Aber es ist eben ein riesiger Single Point of Failure! Das Master-Passwort schützt mich vor einem Passwort-Hack bei Google, aber es hilft nicht, wenn der Angreifer die lokale Passwort-Datenbank (sqlite-Format) auslesen kann. Und genau das war beim AUR-Angriff der Fall. Die Konsequenz: Ich werde in Zukunft die Anzahl der so synchronisierten Passwörter auf ein absolutes Minimum reduzieren und länger nicht benutzte Passwörter löschen bzw. woanders speichern. Der naheliegende Ort wäre natürlich ein Passwort-Manager. Ich muss aber gestehen, dass ich diesen Programmen gegenüber auch skeptisch bin. Sie ersetzen einen Single Point of Failure durch einen anderen. Wer mit plattformübergreifenden Tools positive Erfahrungen gemacht hat, darf seine/ihre Erfahrungen gerne in den Kommentaren teilen :-) Einmal mehr die Distributionsfrage Auf meinem Linux-Notebook werde ich die aktuelle Parallel-Installation von Arch Linux und CachyOS bei nächster Gelegenheit durch Fedora ersetzen. Ich habe das Notebook zuletzt fast nur noch unterwegs verwendet. Im Büro habe ich mit dem Framework Desktop eine attraktivere Alternative. Dort habe ich mich im Rahmen meiner KI-Arbeiten gut an Fedora gewöhnt. Zu glauben, Fedora sei frei von den skizzierten Gefahren, wäre natürlich naiv. Aber vermutlich sind die Risiken bei großen, weit verbreiteten Distributionen mit kommerziellem Hintergrund (Fedora ist ja eine Art offizielle Spielwiese von Red Hat) doch geringer als bei kleineren Distributionen — auch, was weit verbreitete, aber eben inoffizielle Paketquellen für Zusatzpakete angeht. Alleine schon die Trennung über mehrere Einzel-Repos anstelle des zentralen AUR-Verzeichnisses ist schon ein Vorteil. Der Abschied von Arch Linux fällt mir schwer. Ich empfinde das Rolling-Release-Modell äußerst attraktiv. Arch Linux hat über mehrere Jahre sehr gut für mich funktioniert. Aber ich werde auch in Zukunft nicht ganz ohne externe Pakete auskommen. Mit AUR habe ich mir die Finger einmal verbrannt. Diese Art der Verwaltung externer Pakete ist vielleicht doch zu liberal; Paketmanager wie yay oder paru verschleiern das Risiko zu sehr. Ein zweites Mal will ich dieses Risiko nicht eingehen. Quellen, Links https://ioctl.fail/preliminary-analysis-of-aur-malware/ https://github.com/lenucksi/aur-malware-check (Test-Scripts, ob Sie betroffen sind) https://kofler.info/infos-zur-arch-linux-attacke
Am 11.6. 2026 entdeckten Sicherheitsforscher kompromittierte AUR-Pakete in Arch Linux (AUR = Arch User Repository). Zwischenzeitlich waren ca. 1600 AUR-Pakete betroffen. AUR-Pakete sind nicht offizielle Zusatzpakete, die kein dezidiertes Prüfverfahren durchlaufen. Die Installation erfolgt häufig über einsteigerfreundliche Tools wie yay oder paru. Der Angriff erfolgte durch die Modifizierung der PKGBUILD-Dateien von Paketen, die als verwaist … Infos zur Arch-Linux-Attacke weiterlesen →
Am 11.6. 2026 entdeckten Sicherheitsforscher kompromittierte AUR-Pakete in Arch Linux (AUR = Arch User Repository). Zwischenzeitlich waren ca. 1600 AUR-Pakete betroffen. AUR-Pakete sind nicht offizielle Zusatzpakete, die kein dezidiertes Prüfverfahren durchlaufen. Die Installation erfolgt häufig über einsteigerfreundliche Tools wie yay oder paru. Der Angriff erfolgte durch die Modifizierung der PKGBUILD-Dateien von Paketen, die als verwaist (orphaned) galten, für die es also keinen Maintainer mehr gab. Aufgrund der veränderten PKGBUILD-Datei wurde zusätzlich zum Paket Schadsoftware installiert. Ziel des Angriffs ist offensichtlich das Einsammeln von Passwörtern aus Firefox- und Chromium-basierten Browsern sowie von SSH-Keys und anderer sensibler Daten. Die Informationen dazu sind noch spärlich. Ob ich selbst betroffen bin, kann ich aktuell nicht mit Sicherheit sagen; auf meinem Linux-Notebook habe ich zwei oder drei Tage vor Bekanntwerden das letzte Update durchgeführt. Vorerst habe ich das Gerät stillgelegt und den heutigen Morgen damit verbracht, potentiell betroffene SSH-Keys von diversen Server, GitHub- und GitLab-Accounts zu entfernen :-( An einer Neuinstallation wird kein Weg vorbeiführen. Detaillierte Informationen finden Sie hier: https://ioctl.fail/preliminary-analysis-of-aur-malware/ https://www.sonatype.com/blog/atomic-arch-npm-campaign-adds-malicious-dependency https://cybersecuritynews.com/arch-linux-aur-packages-compromised/ https://linuxnews.de/massiver-angriff-auf-das-aur-ueber-400-pakete-kompromittiert/ https://lists.archlinux.org/archives/list/aur-general@lists.archlinux.org/thread/FGXPCB3ZVCJIV7FX323SBAX2JHYB7ZS4/ (Diskussion auf dem Arch-Linux-Forum) https://md.archlinux.org/s/SxbqukK6IA (Liste der betroffenen Pakete, inoffiziell, Stand 13.6.2026) https://github.com/lenucksi/aur-malware-check (Test-Scripts, ob Sie betroffen sind) Weitere Links https://www.heise.de/news/Angriffswelle-auf-Arch-Linux-Hunderte-Paketbeschreibungen-mit-Malware-im-AUR-11330029.html https://www.phoronix.com/news/Arch-Linux-AUR-More-Than-1500 https://www.archlinux.de/news/35807-Aktuelle-Aktivitaeten-schaedlicher-Pakete-im-AUR (spärliche Informationen) https://wiki.archlinux.org/title/Arch_User_Repository (Erklärung, was AUR-Pakete sind)
Im April oder Mai 2026 habe ich einen denkwürdigen Meilenstein erreicht: Laut meinen Aufzeichnungen wurden eine Million meiner Bücher verkauft. Ein guter Anlass für einen beruflichen Rückblick und ein Dankeschön! Die erste Million fällt zufälligerweise mit einem anderen Jubiläum zusammen: Vor 40 Jahren habe ich mit der Arbeit an meinem ersten Buch begonnen, dem Atari … Die erste Million (1.000.000 📚) weiterlesen →
Im April oder Mai 2026 habe ich einen denkwürdigen Meilenstein erreicht: Laut meinen Aufzeichnungen wurden eine Million meiner Bücher verkauft. Ein guter Anlass für einen beruflichen Rückblick und ein Dankeschön! <img decoding="async" src="https://kofler.info/wp-content/uploads/regal-2026-04-1920.jpg" alt="" width="1920" height="842" class="size-full wp-image-9620" srcset="https://kofler.info/wp-content/uploads/regal-2026-04-1920.jpg 1920w, https://kofler.info/wp-content/uploads/regal-2026-04-1920-850x373.jpg 850w, https://kofler.info/wp-content/uploads/regal-2026-04-1920-1280x561.jpg 1280w, https://kofler.info/wp-content/uploads/regal-2026-04-1920-768x337.jpg 768w, https://kofler.info/wp-content/uploads/regal-2026-04-1920-1536x674.jpg 1536w" sizes="(max-width: 1920px) 100vw, 1920px" /> Die gesammelten Werke (Stand Anfang April 2026) Die erste Million fällt zufälligerweise mit einem anderen Jubiläum zusammen: Vor 40 Jahren habe ich mit der Arbeit an meinem ersten Buch begonnen, dem Atari ST Grafikbuch (mehr Details hier). Dieses Buch war ein Mittelding zwischen Abenteuer, Hobby und Ferialjob. Nie hatte ich damals gedacht, dass das Schreiben zu meinem Beruf werden könnte. <img loading="lazy" decoding="async" src="https://kofler.info/wp-content/uploads/atari-grafik1.jpg" alt="" width="500" height="470" class="size-full wp-image-2388" srcset="https://kofler.info/wp-content/uploads/atari-grafik1.jpg 1000w, https://kofler.info/wp-content/uploads/atari-grafik1-533x500.jpg 533w, https://kofler.info/wp-content/uploads/atari-grafik1-768x720.jpg 768w" sizes="auto, (max-width: 500px) 100vw, 500px" /> Das Atari-ST-Grafikbuch (1. Auflage 1987) Während meines Elektrotechnik-Studiums folgten weitere Bücher zu GfA-Basic, Visual Basic und Mathematica (ein Computer-Algebra-Programm). Die Bücher habe ich überwiegend in den Sommerferien geschrieben. Charakteristisch für diese Zeit war meine grenzenlose Begeisterung für die IT: Der erste, zweite, dritte Computer! (1984: Oric 1, 1986: Atari ST, vermutlich 1990: der erste PC von Vobis) Das erste Programm in Maschinencode (6502) bzw. Assembler (Motorola 68000)! GfA-Basic, ein für die damalige Zeit modernes Basic samt vernünftigem Editor. Dann Visual Basic! Mir war sofort klar, welches Potenzial diese (beinahe erste) grafische IDE hatte. Mathematica! Da hatte ich jahrelang Mathematikvorlesungen besucht, integrieren und Differenzialgleichungen lösen gelernt, und plötzlich gab es ein Programm, das symbolisch rechnen konnte! Aus damaliger Perspektive war das so eindrucksvoll wie vor wenigen Jahren das erste Mal ChatGPT auszuprobieren. Ich empfand es großartig, diese Programme erkunden und dokumentieren zu dürfen — und damit auch noch Geld zu verdienen. Software mit all ihren Stärken und Schwächen zu beschreiben, wie sie in der Praxis wirklich funktionierten. (Halten Sie sich die Zeit vor Augen: Es gab damals noch kein öffentlich zugängliches Internet. Die einzige Dokumentation war ein mitgeliefertes, meist miserables Handbuch. Vereinzelt noch Zeitschriftenartikel.) Erst mit Abschluss von Studium und Zivildienst stellte sich die Frage: Weiter schreiben oder einen »richtigen« Beruf ergreifen? Ich entschied mich für die Selbstständigkeit — und hatte Glück: Zwei, drei Jahre später überschritt ich mit Visual Basic 3 zum ersten Mal die 10.000-Stück-Auflage. Aus meiner Sicht begann damals ein goldenes Zeitalter. Das Interesse an der IT war riesig, und ich hatte (zumindest manchmal) einen guten Riecher für die spannendsten Themen. Für wenige Jahre war ich Bestseller-Autor, zumindest im Maßstab von IT-Büchern. <img loading="lazy" decoding="async" src="https://kofler.info/wp-content/uploads/kofler-translations.jpg" alt="" width="1920" height="691" class="size-full wp-image-9674" srcset="https://kofler.info/wp-content/uploads/kofler-translations.jpg 1920w, https://kofler.info/wp-content/uploads/kofler-translations-850x306.jpg 850w, https://kofler.info/wp-content/uploads/kofler-translations-1280x461.jpg 1280w, https://kofler.info/wp-content/uploads/kofler-translations-768x276.jpg 768w, https://kofler.info/wp-content/uploads/kofler-translations-1536x553.jpg 1536w" sizes="auto, (max-width: 1920px) 100vw, 1920px" /> Einige Bücher sind auch als Übersetzungen erschienen Eine erste berufliche Zeitenwende war das Internet. Plötzlich gab es kostenlose, stets aktuelle Information — eine gewaltige Konkurrenz zu Büchern. Die Verkaufszahlen sanken, aber der Internet-Hype, stets neue Programmiersprachen, der Durchbruch von Open-Source-Software schufen gleichzeitig neue Möglichkeiten. Die Ausgesetztheit und das Risiko des selbstständigen Arbeitens wurden mir erstmals 2013 vollständig klar. Addison-Wesley, der Verlag, für den ich über 20 Jahre praktisch exklusiv geschrieben hatte, wurde innerhalb von Monaten abgewickelt und geschlossen. Ich hatte damals den Verdacht, dass die Zeit der IT-Bücher vorbei wäre. Erfreulicherweise fand ich beim Rheinwerk Verlag (ehemals Galileo Press) eine neue Heimat und bin dort sehr glücklich (siehe auch hier). Mit ChatGPT & Co. hat ein neuer Umbruch begonnen: KI-Tools stellen die ganze IT-Branche auf den Kopf und verkleinern das Zielpublikum für Coding-Bücher dramatisch. Natürlich ergeben sich auch damit neue Chancen. Unser Buch Coding mit KI steckt ab, was aktuell technisch möglich ist — und das ist absolut faszinierend! In gewisser Weise schließt sich mit dem Thema »Künstliche Intelligenz« der Kreis dieses Rückblicks: Die Faszination, die ich als Jugendlicher für die ersten Computer empfand, ist nach wie vor da. Heute richtet sie sich auf die Möglichkeiten, die KI-Tools bieten. Was wird morgen kommen? Danke! Leserinnen und Leser: Hätten Sie nicht immer wieder meine Bücher gekauft, auf Amazon hoch bewertet und in Ihrem beruflichen und privaten Umfeld weiterempfohlen, wäre mein berufliches Dasein nicht möglich gewesen. Danke, danke, danke! Verlag/Lektorat/Herstellung: Ich schreibe meine Bücher selbst (im KI-Zeitalter ist das ja nicht mehr selbstverständlich), aber ein Buch entsteht doch nie alleine. Einen ganz wesentlichen Einfluss hat der Verlag und dort speziell das Lektorat. Es spricht bei der Planung des Buchs, bei der inhaltlichen Ausrichtung, der Korrektur, dem Layout, dem Titelbild, beim Marketing und der Werbung mit. Ohne die Mithilfe des Verlags sind erfolgreiche Bücher praktisch unmöglich. Im Verlauf von vier Jahrzehnten hatte ich durchwegs großartige und engagierte Lektorinnen und Lektoren, von denen ich die wichtigsten hier namentlich nennen möchte: Norbert Hesselmann (der Lektor meines ersten Buchs, Sybex), Irmgard Wagner und Boris Karnikowski (beide prägten meine Zeit bei Addison-Wesley) sowie Sebastian Kestel und Christoph Meister (beide waren/sind im Rheinwerk Verlag tätig). Eine besondere Rolle im Verlag nimmt die Herstellung ein: Diese Abteilung des Verlags ist verantwortlich dafür, dass Bücher in ordentlichem Layout gesetzt und dann gedruckt werden, dass E-Books in allen erdenklichen Formaten zur Verfügung stehen usw. Aus historischen Gründen setze ich die meisten Bücher selbst, früher mit LaTeX, jetzt mit einem Docker-Setup bestehend aus Markdown, Pandoc und LuaTeX. Dass ich selbst setzen kann und darf, ist ein absoluter Sonderfall; ich bedanke mich ausdrücklich bei Norbert Englert (Rheinwerk Verlag) für seine Unterstützung. Meine Schreibumgebung unter Linux, links ein PDF-Viewer, oben Emacs, unten ein Terminal. Dasselbe Docker-Setup funktioniert eins zu eins auch unter macOS (und theoretisch sogar unter Windows). Co-Autoren: Im Lauf der Zeit habe ich ein halbwegs solides IT-Wissen erworben, aber es gibt doch Grenzen :-) Viele meiner Bücher wären/sind ohne die Team-Arbeit mit Co-Autoren unmöglich. Die zahlreichen Kooperationen waren immer äußerst produktiv und für mich sehr lehrreich. Mit Bernd Öggl (erster gemeinsamer Titel 2004: PHP und MySQL) ist daraus sogar eine langjährige berufliche Zusammenarbeit und private Freundschaft entstanden. Antworten auf Fragen, die Sie nie gestellt haben Kann man vom Bücherschreiben leben? Normalerweise nicht, in meinem Fall schon. Die ersten Jahre war das Schreiben von Computer-Büchern ein Mittelding zwischen Hobby und einem netten Zuverdienst neben dem Studium. Danach wurde das Schreiben mein Beruf; seit über 30 Jahren sind Bücher meine Haupteinnahmequelle. Einige Jahre habe ich (für meine Begriffe) großartig verdient, die restliche Zeit ganz passabel. <img loading="lazy" decoding="async" src="https://kofler.info/wp-content/uploads/kofler-work.jpg" alt="" width="1422" height="1920" class="size-full wp-image-9675" srcset="https://kofler.info/wp-content/uploads/kofler-work.jpg 1422w, https://kofler.info/wp-content/uploads/kofler-work-481x650.jpg 481w, https://kofler.info/wp-content/uploads/kofler-work-711x960.jpg 711w, https://kofler.info/wp-content/uploads/kofler-work-768x1037.jpg 768w, https://kofler.info/wp-content/uploads/kofler-work-1138x1536.jpg 1138w" sizes="auto, (max-width: 1422px) 100vw, 1422px" /> Im frisch renovierten Büro mit neuem Buchregal Macht das wirklich Spaß? Ja! Je neuartiger das Thema, desto besser. (Die zehnte Überarbeitung eines Buchs ist zugegebenermaßen weniger lustig.) Ich bin ja nicht ausschließlich Autor, sondern unterrichte gelegentlich an einer Fachhochschule, entwickle Software und administriere Server. Aber bei weitem die liebste Tätigkeit ist für mich das Konzipieren eines neuen Buchs, das Recherchieren und Ordnen von Informationen, das Verfassen von verständlichen Anleitungen und Erklärungen. Noch ein Argument für das Schreiben: die freie Zeiteinteilung. Kurz und gut: Ich habe es immer als Privileg empfunden, vom Schreiben leben zu können. Stimmt das mit der Million überhaupt? Ich bekomme je nach Verlag viertel-, halb- oder ganzjährig Abrechnungen mit Verkaufszahlen. Diese landen in einer großen LibreOffice-Calc-Datei. 95% der Million sind so belegt. Der Rest entfällt auf E-Books und Übersetzungen, für die ich zwar Geld, aber keine detaillierten Abrechnungen erhalten habe. Ich habe die Zahlen konservativ geschätzt, aber ich gebe zu: Ganz genau kann ich es nicht sagen. Vielleicht habe ich die Million schon im Februar erreicht, vielleicht ist es erst im Juli so weit. Ich denke, es spielt keine Rolle. Welche Bücher haben sich am besten verkauft? Auf Platz eins steht natürlich mein Linux-Buch, dessen zahlreiche Auflagen fast ein Drittel zur Million beitrugen. Andere Bestseller waren Visual Basic, Raspberry Pi, Excel VBA, Hacking & Security und der Python-Grundkurs. Wie geht es weiter? Wenn es nach mir geht: Auf zur nächsten Million! Realistisch gesehen haben IT-Fachbücher aber ihren Zenit überschritten. Speziell Programmiertitel kämpfen gegen die KI-Konkurrenz. IT-Studien leiden unter sinkenden Studentenzahlen. Konkret heißt das: Es wird Neuauflagen bzw. neue Bücher geben, solange Sie sie kaufen :-) PS: Bitte nehmen Sie sich hin und wieder Zeit für eine kurze Rezension! Das ist ein Zeichen der Wertschätzung für mich und eine Orientierungshilfe für andere. Ja, auch wenn die Links zu Amazon von dieser Website verschwunden sind, gerne dort. Auf Amazon werden die Rezensionen nämlich gelesen, selbst von Leuten, die dort nicht bestellen. Quellen/Links https://kofler.info/ueber/bibliografie https://kofler.info/ueber/uebersetzungen https://kofler.info/30-jahre-linux-buch https://kofler.info/10-jahre-beim-rheinwerk-verlag https://kofler.info/20-jahre-linux-buch https://kofler.info/30-jahre-buchautor
Vor gut zweieinhalb Jahren habe ich hier über pip-Probleme berichtet, die unter aktuellen Ubuntu- und Debian-Systemen aufgetreten sind: externally-managed-environment (PEP 668) verhinderte lokale pip-Installationen wegen Konflikten zwischen System-Paketen. Die damals beschriebenen Lösungen, insbesondere das Einrichten eines virtuellen Environments, funktionieren weiterhin. Aber inzwischen gibt es eine bessere Option: uv ist ein schneller, moderner Paketmanager für Python, … Python-Modulmanager uv weiterlesen →
Vor gut zweieinhalb Jahren habe ich hier über pip-Probleme berichtet, die unter aktuellen Ubuntu- und Debian-Systemen aufgetreten sind: externally-managed-environment (PEP 668) verhinderte lokale pip-Installationen wegen Konflikten zwischen System-Paketen. Die damals beschriebenen Lösungen, insbesondere das Einrichten eines virtuellen Environments, funktionieren weiterhin. Aber inzwischen gibt es eine bessere Option: uv ist ein schneller, moderner Paketmanager für Python, der pip, venv, pipx und noch einige andere Tools auf einmal ersetzt. Wer regelmäßig Python-Module installiert, sollte sich die paar Minuten nehmen, uv kennenzulernen. Es lohnt sich. Update 8.6.2026: uv und Cron Update 31.7.2026: uv 0.12 mit neuem Init-Verhalten (src-Verzeichnis) Das pip-Problem Zuerst eine kurze Wiederholung meines alten Artikels: Bei immer mehr Linux-Distributionen verhindert PEP 668, dass pip install systemweit Pakete installiert. Stattdessen erscheint die Fehlermeldung externally-managed-environment. Es gibt zwei Auswege: entweder installieren Sie das Python-Modul als Distributionspaket (falls verfügbar), oder sie richten ein Virtual Environment, also ein projektspezifisches Verzeichnis mit eigenen, isolierten Modul-Installationen. Das Einrichten eines Virtual Environments mit python3 -m venv .venv ist nicht schwierig, aber umständlich. Man muss es bei jedem neuen Terminal-Fenster aktivieren (source .venv/bin/activate oder eine Variante dieses Kommandos für Zsh, Fish oder PowerShell), eine requirements.txt pflegen und bei der Weitergabe des Projekts dem Empfänger erklären, was er zu tun hat. uv macht das alles einfacher. Was ist uv? uv ist in der Programmiersprache Rust entwickelt worden und stammt von der Firma Astral. Im März 2026 hat OpenAI Astral übernommen; das Team arbeitet seitdem in der Codex-Abteilung. Ob und wie das die Weiterentwicklung von uv beeinflusst, ist noch nicht absehbar. Das Projekt bleibt aber Open Source (https://github.com/astral-sh/uv). Was uv von pip unterscheidet: Es ersetzt pip, venv, pip-tools, pipx und pyenv in einem einzigen Binary. Es ist laut eigenen Benchmarks 10- bis 100-mal schneller als pip. Es verwaltet Abhängigkeiten in pyproject.toml und einer Lock-Datei. Das manuelle Pflegen von requirements.txt ist damit vorbei. Allein im Februar 2026 wurde uv über 126 Millionen Mal heruntergeladen. Es hat sich als De-facto-Standard für neue Python-Projekte etabliert. Auch bei meinen eigenen Python-Projekten ist uv inzwischen eine Selbstverständlichkeit geworden. Das Kommando ist einfach zu bedienen und funktioniert gut. uv installieren uv wird unabhängig von Python installiert. Unter macOS gelingt das am einfachsten mit Homebrew: brew install uv Bei manchen Linux-Distributionen steht uv als Paket zur Verfügung (apt install uv, dnf install uv). Falls nicht, funktioniert dieses Vorgehen: curl -LsSf https://astral.sh/uv/install.sh -o uv_install.sh less uv_install.sh # kurze Kontrolle sh uv_install.sh Das Script gibt am Ende Hinweise, wie .local/bin zur PATH-Variablen hinzuzufügen ist. Unter Windows führen Sie folgende PowerShell-Kommandos aus: powershell -ExecutionPolicy ByPass ` -c "irm https://astral.sh/uv/install.ps1 | iex" $env:Path = "C:\Users\<accountname>\.local\bin;$env:Path" Nach der Installation überzeugen Sie sich kurz davon, dass alles geklappt hat: uv --version uv 0.11.19 (...) Updates führen Sie mit brew upgrade uv (macOS) bzw. durch Wiederholung des Installations-Kommandos durch. Weitere Installationstipps finden Sie auf der GitHub-Seite. Neues Projekt einrichten Nehmen wir an, Sie entwickeln ein Script, das die Module requests und beautifulsoup4 benötigt. Die folgenden Kommandos richten das Projekt ein: uv init my-webscraper # erzeugt das Projektverzeichnis cd my-webscraper # dorthin wechseln uv add requests beautifulsoup4 # Module installieren Falls es schon ein Projektverzeichnis gibt, wechseln Sie mit cd dorthin und führen uv init . aus. uv init erzeugt ein Projektverzeichnis mit folgender Struktur: my-webscraper/ ├── .gitignore ├── .python-version ├── .venv/ ├── main.py ├── pyproject.toml └── README.md uv init kümmert sich also um das Virtual Environment im Verzeichnis .venv. uv add installiert das gewünschte Modul und trägt es in pyproject.toml ein. Hinweis: Die Datei .gitignore wird nicht erzeugt bzw. verändert, wenn das aktuelle Verzeichnis bereits unter Git-Kontrolle steht. In diesem Fall sollten Sie selbst in .gitignore eine Regel einbauen, die das Verzeichnis .venv ignoriert. Ihr Script führen Sie mit uv run aus: uv run main.py uv run sorgt dafür, dass die richtige Python-Version und das Virtual Environment aktiv sind. Sie müssen sich um nichts weiter kümmern. Weitere Module fügen Sie mit uv add hinzu, überflüssige entfernen Sie mit uv remove. Normalerweise verwendet uv einfach die gerade installierte Python-Version. Wenn Sie ausnahmsweise für ein Projekt eine andere Version benötigen, installieren und fixieren Sie diese: uv python install 3.12 uv python pin 3.12 Projektweitergabe uv pflegt mehrere Dateien für die Projektverwaltung: pyproject.toml enthält die Abhängigkeiten des Projekts. uv.lock enthält die exakten Versionsnummern aller installierten Module. .python-version enthält die gewünschte Python-Version. Wenn Sie Ihr Projekt weitergeben oder auf einem anderen Rechner einsetzen möchten, geben Sie neben dem Quellcode die ersten beiden Dateien weiter, falls die Python-Version wichtig ist, auch die dritte. Die Empfängerin kann das Projekt dann sofort ausführen: uv run main.py uv erkennt pyproject.toml und uv.lock, richtet das Virtual Environment ein und installiert alle erforderlichen Module — vollautomatisch, ohne weitere Anweisungen. Ältere Projekte mit requirements.txt Bei bestehenden Projekten, die noch requirements.txt verwenden, bietet uv ebenfalls Unterstützung: uv venv # Virtual Environment einrichten uv pip install -r requirements.txt # Abhängigkeiten installieren Bestehende Projekte auf uv migrieren Wer ein vorhandenes Projekt von pip auf uv umstellen möchte, beginnt mit uv init --bare im Projektverzeichnis. Das Flag --bare verhindert, dass Beispieldateien erzeugt oder vorhandene Dateien überschrieben werden. Als Ergebnis erscheint eine minimale pyproject.toml. Im nächsten Schritt importieren Sie die bisherigen Abhängigkeiten aus requirements.txt: cd my-project uv init --bare uv add -r requirements.txt uv add -r requirements.txt trägt alle Module in pyproject.toml ein und erzeugt gleichzeitig uv.lock mit den exakten Versionsnummern. Mit uv sync installiert uv anschließend alle Module in einem neuen .venv-Verzeichnis — ohne manuelles Aktivieren der Umgebung. Ab jetzt führen Sie Ihr Script mit uv run aus. Nach erfolgreicher Migration geben Sie künftig pyproject.toml und uv.lock weiter — requirements.txt können Sie löschen. Falls CI-Systeme oder Docker-Builds weiterhin eine requirements.txt benötigen, lässt sie sich jederzeit automatisch aus der Lock-Datei erzeugen: uv export --format requirements-txt > requirements.txt Python-Tools global installieren uv ersetzt auch pipx: Mit uv tool install installieren Sie in Python entwickelte Kommandozeilen-Tools direkt auf Ihrem Rechner, außerhalb eines Projektverzeichnisses. Die Tools landen in .local/share/uv/tools, Links dazu werden in .local/bin angelegt: uv tool install httpie httpie --version 3.2.4 Noch praktischer ist uvx: Damit führen Sie ein Tool aus, ohne es permanent zu installieren. uv lädt die erforderlichen Dateien in ein Cache-Verzeichnis und führt das Tool sofort aus — ideal für die gelegentliche Nutzung: uvx ruff check . # überprüft alle Python-Dateien im Verzeichnis Mit uv cache clean löschen Sie bei Bedarf die zwischengespeicherten Dateien. uv und Cron Wer ein Python-Script per Cron automatisch ausführen möchte, stößt auf zwei Probleme: Erstens ist uv häufig lokal installiert, meist in .local/bin/uv. Cron verwendet eine minimale PATH-Variable und findet das Kommando uv daher nicht. Zweitens setzt uv run voraus, dass das aktuelle Verzeichnis das Projektverzeichnis ist — das ist beim Aufruf per Cron ebenfalls nicht der Fall. Theoretisch könnten Sie beide Probleme durch die Angabe absoluter Pfaden in der crontab-Datei lösen. Eleganter ist es aber, ein kleines Wrapper-Script zu schreiben: # Datei /home/user/myproject/run.sh cd /home/user/myproject /home/user/.local/bin/uv run main.py Dieses Script rufen Sie dann aus Cron auf: # /etc/crontab 0 8 * * * user /home/user/myproject/run.sh user ersetzen Sie jeweils durch Ihren Benutzernamen. Vergessen Sie nicht, das Script ausführbar zu machen (chmod +x run.sh). uv 0.12 mit geändertem Init-Verhalten Mit Version 0.12 hat sich das Verhalten von uv init geändert. Bisher hat uv init einfach main.py eingerichtet. Jetzt ist die Default-Verzeichnisstruktur verschachtelt: tree . ├── pyproject.toml ├── README.md └── src └── <projektname> └── __init__.py Wenn Sie also uv init my-project aufrufen, erzeugt uv das Verzeichnis src/my-project und speichert dort __init__.py. Den resultierenden Start-Code in __init__.py können Sie nun mit uv run my-project aufrufen. Die Verzeichnisstruktur entspricht den Python-Empfehlungen für Module. Die src-Verschachtelung mag für große Projekte zweckmäßig sein. Wenn Sie mit uv ein kleines Script einrichten, ist die Verschachtelung aber unnötig. Es hindert Sie niemand daran, weiterhin direkt im Projektverzeichnis my-script.py einzurichten und dieses mit uv run my-script.py auszuführen. Quellen/Links https://peps.python.org/pep-0668 https://docs.astral.sh/uv https://docs.astral.sh/uv/guides/migration/pip-to-project/ https://github.com/astral-sh/uv https://github.com/astral-sh/uv/releases/tag/0.12.0 https://docs.python.org/3/tutorial/modules.html#packages https://simonwillison.net/2026/Mar/19/openai-acquiring-astral https://dasroot.net/posts/2026/05/uv-openai-python-supply-chain-acquisition-risks/ https://kofler.info/hilfe-pip-funktioniert-nicht-mehr/
Wer mein Linux-Buch gelesen hat weiß, dass ich nicht im Vi-Lager zuhause bin, sondern zu den Emacs-Fans zähle. Beim Programmieren verwende ich diverse Editoren und IDEs, von VSCode über IntelliJ bis hin zu Xcode. Aber längere Texte (sprich: Bücher) schreibe ich seit Jahrzehnten ausschließlich mit dem Emacs. Ich habe ein paar halbherzige Versuche mit anderen … Emacs als Markdown-Editor weiterlesen →
Wer mein Linux-Buch gelesen hat weiß, dass ich nicht im Vi-Lager zuhause bin, sondern zu den Emacs-Fans zähle. Beim Programmieren verwende ich diverse Editoren und IDEs, von VSCode über IntelliJ bis hin zu Xcode. Aber längere Texte (sprich: Bücher) schreibe ich seit Jahrzehnten ausschließlich mit dem Emacs. Ich habe ein paar halbherzige Versuche mit anderen Editoren gemacht, aber ich bin immer wieder zurückgekommen. Meine Emacs-Liebe hat weniger mit der Großartigkeit dieses Programms zu tun als viel mehr damit, dass ich mir im Laufe der Zeit ein eigenes Setup mit Tastenkürzeln und Zusatzfunktionen gebastelt habe. Davon bin ich jetzt abhängig, meine Finger wollen sich nicht mehr umgewöhnen. <img loading="lazy" decoding="async" src="https://kofler.info/wp-content/uploads/emacs-markdown-1.png" alt="" width="2284" height="1896" class="size-full wp-image-9657" srcset="https://kofler.info/wp-content/uploads/emacs-markdown-1.png 2284w, https://kofler.info/wp-content/uploads/emacs-markdown-1-783x650.png 783w, https://kofler.info/wp-content/uploads/emacs-markdown-1-1156x960.png 1156w, https://kofler.info/wp-content/uploads/emacs-markdown-1-768x638.png 768w, https://kofler.info/wp-content/uploads/emacs-markdown-1-1536x1275.png 1536w, https://kofler.info/wp-content/uploads/emacs-markdown-1-2048x1700.png 2048w" sizes="auto, (max-width: 2284px) 100vw, 2284px" /> Eine Markdown-Datei aus meinem Scripting-Buch im Emacs. Beachten Sie, dass die Listenpunkte intern zwar sehr lange Textzeilen sind, dass diese aber umbrochen und richtig eingerückt angezeigt werden. Der Umbruch ist auf max. 100 Zeichen limitiert, passt sich aber automatisch an eine kleinere Fensterbreite an. Die Motivation für diesen Blogbeitrag ist die immer wiederkehrende Frage, womit ich meine Markdown-Texte verfasse. Vielleicht finden andere Emacs-Fans in der nachfolgenden .emacs-Datei Ideen, die sie noch nicht kennen; vielleicht schreibt mir auch jemand im Forum, welches Feature ich bisher übersehen habe. Dieser Beitrag ist aber keinesfalls ein Versuch, Sie vom Emacs zu überzeugen. Ein Neustart heute bei Null — da würde ich höchstwahrscheinlich bei einem deutlich moderneren Programm landen (möglicherweise bei zed). Dieser Text will Ihnen auch nicht meine Tastenkürzel aufzwingen. Die sind im Laufe der Zeit eher zufällig entstanden. Aber dieser Teil von .emacs lässt sich ja am einfachsten anpassen. Die Datei .emacs Die Konfiguration des Emacs erfolgt in der Datei .emacs. Die Anweisungen dort müssen in der Programmiersprache Elisp formuliert werden. Das ist die Emacs-Variante der heute ansonsten kaum noch gebräuchlichen Sprache Lisp. Früher war Elisp eine Hürde für viele Emacs-Einsteiger, und in einigen frühen Auflagen meines Linux-Buchs hatte ich sogar ein kurzes Elisp-Kapitel untergebracht. Heute sagen Sie Claude oder einem anderen KI-Tool, was Sie erreichen wollen, schon bekommen Sie den erforderlichen Code. (Manchmal klappt es erst im zweiten oder dritten Versuch.) Dank KI ist die Elisp-Syntaxhürde also überwunden. Der Emacs liest .emacs automatisch beim Start. Spätere Änderungen gelten daher erst mit dem nächsten Start oder indem Sie die geänderten Zeilen markieren und mit Alt+X eval-region Return ausführen. Meine Konfiguration Die ersten Zeilen im folgenden Listing aktivieren einige allgemeine Einstellungen. cua-mode erlaubt die vertrauten Tastenkürzel Strg+C, Strg+X und Strg+V für Kopieren, Ausschneiden und Einfügen. Im originalen Emacs gibt es dafür andere Kürzel, die parallel aktiv bleiben. save-place-mode bewirkt, dass der Emacs die letzte Cursor-Position in jeder geöffneten Datei dauerhaft speichert. Damit das Arbeitsverzeichnis nicht mit Backup-Dateien übersät wird, landen Emacs-Backups gesammelt in ~/.emacs.d/backups/. Moderne Emacs-Konfigurationen laden Erweiterungspakete über package.el nach. Das Standard-Repository des Emacs enthält nur wenige Pakete; deshalb binde ich MELPA ein, das mit Abstand größte Community-Repository mit Tausenden von Erweiterungen. Beim ersten Start auf einem neuen Rechner aktualisiert der Emacs automatisch die Paketliste (package-refresh-contents), sodass alle benötigten Pakete sofort installiert werden können. Das Makro use-package bündelt je ein Paket zusammen mit seiner Konfiguration, Hooks und Tastenkürzel-Bindungen in einem einzigen Block. Die Einstellung use-package-always-ensure t sorgt dafür, dass fehlende Pakete automatisch nachinstalliert werden, ohne manuelles Eingreifen. Der markdown-mode aus dem gleichnamigen Paket steht im Zentrum des Setups. Der Modus hebt Markdown-Syntax farbig hervor und aktiviert über Hooks mehrere Begleitmodi: visual-line-mode sorgt für weiche Zeilenumbrüche ohne harte Zeilenenden in der Datei, display-line-numbers-mode blendet Zeilennummern ein, und visual-fill-column-mode begrenzt die Textbreite auf 100 Zeichen. adaptive-wrap ist ein kleines, aber feines Detail: Wenn eine Zeile weich umgebrochen wird, rückt die Folgezeile so ein, dass Listenelemente (* oder -) korrekt untereinander ausgerichtet bleiben. unfill ergänzt den eingebauten Befehl fill-paragraph (bei mir F4): Statt einen Absatz auf mehrere kurze Zeilen zu verteilen, fasst unfill-paragraph alle Zeilen eines Absatzes wieder zu einer einzigen langen Zeile zusammen. Das ist hilfreich, wenn Markdown-Quellen von anderen Tools weiterverarbeitet werden. Das Paket vertico erweitert den Emacs-Minibuffer um eine vertikale Auswahlliste (siehe den folgenden Screenshot). Beim Wechsel zwischen Buffern (F1) sehe ich alle offenen Dateien auf einen Blick inklusive Dateigröße, Modus und Pfad — letzteres dank marginalia, das die Listeneinträge um nützliche Zusatzinformationen ergänzt. orderless macht die Suche komfortabler: Ich kann mehrere Suchbegriffe mit Leerzeichen trennen und in beliebiger Reihenfolge eingeben. <img loading="lazy" decoding="async" src="https://kofler.info/wp-content/uploads/emacs-minibuffer.png" alt="" width="2284" height="1324" class="alignnone size-full wp-image-9658" srcset="https://kofler.info/wp-content/uploads/emacs-minibuffer.png 2284w, https://kofler.info/wp-content/uploads/emacs-minibuffer-850x493.png 850w, https://kofler.info/wp-content/uploads/emacs-minibuffer-1280x742.png 1280w, https://kofler.info/wp-content/uploads/emacs-minibuffer-768x445.png 768w, https://kofler.info/wp-content/uploads/emacs-minibuffer-1536x890.png 1536w, https://kofler.info/wp-content/uploads/emacs-minibuffer-2048x1187.png 2048w" sizes="auto, (max-width: 2284px) 100vw, 2284px" /> Die benutzerdefinierte vertico-sort-override-function ändert die Sortierreihenfolge im Buffer-Switcher: Statt alphabetischer Reihenfolge erscheinen die zuletzt verwendeten Buffer ganz oben in der Liste. Bei vielen Dateien finde ich die zuletzt verwendeten Datei schneller. swap-char (F11) vertauscht die zwei Zeichen an der Cursor-Position. Tippfehler wie getsern statt gestern lassen sich damit sofort korrigieren: Cursor auf das erste falsche Zeichen, einmal F11, fertig. change-case (F12) wechselt die Groß- bzw. Kleinschreibung des Zeichens unter dem Cursor. change-word-case (F9) tut dasselbe für den ersten Buchstaben des aktuellen Worts, unabhängig davon, wo im Wort der Cursor gerade steht. point-to-register-1 (F5) / jump-to-register-1 (F6): Mit F5 speichere ich die aktuelle Position, mit F6 springe ich dorthin zurück. Beim Sprung wird gleichzeitig die neue Position gespeichert, sodass ich mit wiederholten F6-Drücken zwischen zwei weit entfernten Textstellen hin- und herspringen kann. Ich finde das praktisch, wenn ich parallel an zwei Stellen eines langen Dokuments arbeite. expand-abbrev-or-dabbrev (F3) versucht zunächst, eine gespeicherte Abkürzung zu expandieren. In .abbrevs_defs habe ich einige solche Abkürzungen gespeichert, z.B. ms für »Microsoft« oder rhel für »Red Hat Enterprise Linux«. Falls keine passt, greift dabbrev-expand und vervollständigt das angefangene Wort anhand von Vorkommen im selben Buffer. Praktisch für lange Schlüsselwörter. Beim Einlesen der .emacs-Datei lädt der Editor automatisch alle erforderlichen Pakete herunter. Wenn dabei Download-Fehler auftreten, müssen Sie eventuell den MELPA-Cache aktualisieren. Dazu führen Sie Alt+X package-refresh-contents Return aus und starten den Emacs dann neu. ;; Datei ~/.emacs ;; ======== Grundeinstellungen ==================================== (cua-mode 1) ;Cut&Paste mit Strg+C/X/V (setq inhibit-startup-message t) ;kein Emacs-Startbildschirm (setq screen-preserve-screen-position t) ;zurück zur letzten Zeile (setq scroll-step 5) ;bei Scrollen Sprünge von 5 Zeilen (column-number-mode 1) ; ... Spaltennummern in der Statusleiste (abbrev-mode 0) ;kein automatisches expand-abbrev (setq require-final-newline t) ;letzte Zeile automatisch mit Return abschließen (save-place-mode) ;Cursor-Position innerhalb der Datei merken ;; automatische Backups nicht im lokalen Verzeichnis, sondern in ~/.emacs.d/backups/ (setq backup-directory-alist `(("." . ,(concat user-emacs-directory "backups")))) (setq auto-save-file-name-transforms `((".*" ,(concat user-emacs-directory "backups/") t))) ;; Spaltenbreite für Zeilennummern (nur Markdown) (setq-default display-line-numbers-width 4) ;; Abkürzungstabelle automatisch laden und speichern ;; Falls ~/.abbrev_defs nicht existiert, leere Datei anlegen (kein Fehler) (let ((abbrev-file "~/.abbrev_defs")) (unless (file-exists-p abbrev-file) (write-region "" nil abbrev-file)) (read-abbrev-file abbrev-file)) (setq save-abbrevs t) ;automat. speichern ;; ======== Packages ================================================ ;; package.el initialisieren und MELPA-Repo hinzufügen (falls erforderlich) (require 'package) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) (package-initialize) ;; Paket-Repo aktualisieren (first run / new machine) (when (not package-archive-contents) (package-refresh-contents)) ;; alle erforderlichen Pakete automatisch laden (unless (package-installed-p 'use-package) (package-install 'use-package)) (require 'use-package) (setq use-package-always-ensure t) ;; scratch-Buffer automatisch speichern (https://github.com/Fanael/persistent-scratch) (use-package persistent-scratch :config (persistent-scratch-setup-default)) ;; weiche Zeilenumbrüche mit Einrückung bei Listen etc. (use-package adaptive-wrap :hook (visual-line-mode . adaptive-wrap-prefix-mode)) ;; Spalte mit Zeilennummern / zentrierter Text (use-package visual-fill-column :hook (markdown-mode . visual-fill-column-mode) :config (setq-default visual-fill-column-width 100) (setq visual-fill-column-width 100)) ;; Markdown-Modus (use-package markdown-mode :mode (("\\.text\\'" . markdown-mode) ("\\.md\\'" . markdown-mode)) :hook ((markdown-mode . visual-line-mode) ; soft-wrap long lines (markdown-mode . display-line-numbers-mode) ; show line numbers (markdown-mode . visual-fill-column-mode) ; center text within column width (markdown-mode . (lambda () (setq fill-column 79))))) ; hard-wrap at 79 chars ;; Unfill: mehrzeilige Absätze zu einer langen Zeile verbinden (Shift+F4) (use-package unfill) ;; mehr Komfort im Minibuffer (use-package vertico :config (vertico-mode 1) ; sort buffer list by 'recently shown' (setq vertico-sort-override-function (lambda (candidates) (if (eq minibuffer-history-variable 'buffer-name-history) (let ((hist (symbol-value minibuffer-history-variable))) (sort candidates (lambda (a b) (let ((pa (or (cl-position a hist :test #'equal) most-positive-fixnum)) (pb (or (cl-position b hist :test #'equal) most-positive-fixnum))) (< pa pb))))) candidates)))) (use-package orderless :config (setq completion-styles '(orderless basic))) (use-package marginalia :config (marginalia-mode 1)) ;; schönere Statuszeile (setzt voraus, dass die JetBrains Nerd Fonts ;; installiert und als Emacs-Font verwendet werden) (use-package nerd-icons :config (setq nerd-icons-font-family "JetBrainsMono Nerd Font")) (use-package doom-modeline :after nerd-icons :config (doom-modeline-mode 1) (setq doom-modeline-height 25) (setq doom-modeline-icon t)) ;; Ligaturen (setzt ebenfalls einen Nerd Font voraus) (use-package ligature :config (ligature-set-ligatures 't '("!=" "!==" "->" "<-" "=>" "<=>" ">=" "<=" "//")) (global-ligature-mode t)) ;; ======== Farben ================================================ (set-face-attribute 'line-number nil :height 0.8 :foreground "#ffffff" :background "#dddddd") (set-face-attribute 'link nil :foreground "RoyalBlue3" :underline nil) ;; für Markdown-Modus (with-eval-after-load 'markdown-mode (set-face-attribute 'markdown-italic-face nil :inherit 'italic :foreground "dark magenta" :slant 'italic) (set-face-attribute 'markdown-pre-face nil :inherit 'font-lock-constant-face)) (with-eval-after-load 'doom-modeline (set-face-attribute 'doom-modeline-buffer-modified nil :foreground "firebrick" :weight 'bold)) ;; ======== eigene Funktionen =================================================== (defun expand-abbrev-or-dabbrev () ;Expansion von Abkürzung: F3 (interactive) (unless (expand-abbrev) ;falls keine Abkürzung existiert (dabbrev-expand nil))) ;dynamische Expansion (defvar my-point-register 1 "Hilfsvariable für jump-to-register-1: merkt sich, welches Register aktiv ist.") (defun point-to-register-1 () ;Position in Reg. 1 speichern: F5 (interactive) (setq my-point-register 1) (point-to-register 1)) (defun jump-to-register-1 () ;Position wechseln: F6 (interactive) ;springt zur Position, die mit F5 (if (= my-point-register 1) ; gespeichert wurde ... (progn (setq my-point-register 2) (point-to-register 2) (jump-to-register 1)) (progn (setq my-point-register 1) (point-to-register 1) (jump-to-register 2)))) (defun swap-char () ;zwei Buchstaben an der Cursor-Position (interactive) ;vertauschen: F11 (save-excursion (forward-char) (transpose-chars 1))) (defun change-case () ;Groß- und Kleinschreibung des Zeichens (interactive) ;an der Cursorposition ändern: F12 (let ((zeichen (char-after (point)))) (if (> zeichen 64) (progn (setq zeichen (logxor zeichen 32)) (insert-char zeichen 1) (delete-char 1)) (forward-char 1)))) (defun change-word-case () ;Groß- und Kleinschreibung des ersten (interactive) ;Zeichens eines Worts verändern: F9 (point-to-register 2) (backward-word 1) (change-case) (jump-to-register 2)) (defun unfill-paragraph-and-advance () ;Absatz zusammenfügen und zum nächsten springen: S-F4 (interactive) (unfill-paragraph) (forward-paragraph) (skip-chars-forward "\n") (recenter)) (defun toggle-fill-column-width () ;Zeilenumbruch zwischen 100 und 1000 Zeichen wechseln (interactive) (setq-local visual-fill-column-width (if (eq visual-fill-column-width 100) 1000 100)) (visual-fill-column-mode 1)) ;; ======== Tastenkürzel ====================================================== (global-set-key [f1] 'switch-to-buffer) ;F1 Buffer wechseln (global-set-key [f2] 'other-window) ;F2 Fenster wechseln (global-set-key [f3] 'expand-abbrev-or-dabbrev) ;F3 Abkürzung erweitern (global-set-key [f4] 'fill-paragraph) ;F4 Absatz umbrechen (global-set-key [S-f4] 'unfill-paragraph-and-advance) ;S-F4 Absatz zusammenfügen + nächster (global-set-key [f5] 'point-to-register-1) ;F5 Position speichern (global-set-key [f6] 'jump-to-register-1) ;F6 zu Position springen (global-set-key [f7] 'goto-line) ;F7 goto line (global-set-key [f8] 'toggle-fill-column-width) ;F8 kurze/lange Zeilen (global-set-key [f9] 'change-word-case) ;F9 Groß/Klein Wort (global-set-key [f10] 'undo) ;F10 Undo (global-set-key [f11] 'swap-char) ;F11 Buchst. vertauschen (global-set-key [f12] 'change-case) ;F12 Groß-/Klein ändern ;; Mac-Tastatur: fn+ctrl+cursor to start/end of buffer (global-set-key [C-prior] 'beginning-of-buffer) (global-set-key [C-next] 'end-of-buffer) ;; Guillemets-Eingabe mit Alt+Q / Shift+Alt+Q (defun insert-guillemot1 () (interactive) (insert "«")) (defun insert-guillemot2 () (interactive) (insert "»")) (global-set-key [?\M-q] 'insert-guillemot1) ;Alt+Q: « (global-set-key [?\M-Q] 'insert-guillemot2) ;Shift+Alt+Q: » ;; macOS: rechte Alt-Taste zur Eingabe von Sonderzeichen wie @ oder € verwenden (when (eq system-type 'darwin) (setq mac-right-option-modifier nil) ; LeftAlt + L -> @ etc. ) Quellen / Links Die oben abgedruckte Datei können Sie als dotemacs.txt herunterladen. https://www.gnu.org/software/emacs/ https://www.gnu.org/software/emacs/documentation.html https://www.gnu.org/software/emacs/manual/html_node/eintr/ https://www.emacswiki.org https://github.com/chrisdone-archive/elisp-guide (Elisp Guide) https://en.wikipedia.org/wiki/Lisp_(programming_language) https://melpa.org/ (Erweiterungspakete) https://github.com/doomemacs/doomemacs (Emacs-Statuszeile) Andere .emacs-Beispiele https://github.com/jackrusher/dotemacs https://sachachua.com/dotemacs/index.html https://protesilaos.com/emacs/dotemacs
Updates zu lokalen Sprachmodelle: MTP, APEX, Qwopus
Adaptive Precision for EXpert Models (APEX)
Unser Buch Coding mit KI ist gerade erst erschienen, schon gibt es spannende Neuigkeiten rund um die Ausführung lokaler Modelle: Multi-Token Prediction (MTP) ist ein ganz neues Feature in llama.cpp. Seit ein paar Tagen steht es auch in LM Studio zur Verfügung. Durch einen »Trick« (Details folgen gleich) kann mit MTP die Output-Token-Geschwindigkeit deutlich vergrößert … Updates zu lokalen Sprachmodelle: MTP, APEX, Qwopus weiterlesen →
Unser Buch Coding mit KI ist gerade erst erschienen, schon gibt es spannende Neuigkeiten rund um die Ausführung lokaler Modelle: Multi-Token Prediction (MTP) ist ein ganz neues Feature in llama.cpp. Seit ein paar Tagen steht es auch in LM Studio zur Verfügung. Durch einen »Trick« (Details folgen gleich) kann mit MTP die Output-Token-Geschwindigkeit deutlich vergrößert werden: laut diversen Benchmarktests im Internet bis auf das Doppelte, in meinen Tests immerhin um ca. 60 bis 70 Prozent. Adaptive Precision for EXpert Models (APEX) ist ein neues Verfahren zur besonders platzsparenden Quantisierung von MoE-Modellen. Der Platzbedarf sinkt je nach Qualitätsstufe auf die Hälfte gegenüber der herkömmlichen 4-Bit-Darstellungen (Q4_x_x). Qwopus ist eine neue Variante zu den Qwen-Modellen, bei denen das Fine Tuning mit Claude Opus verbessert wurde. Von Speculative Decoding zur Multi-Token Prediction In Coding mit KI gehe ich kurz auf das Vorgängerkonzept zu MTP ein, auf Speculative Decoding: Dabei führt die Engine (z.B. llama.cpp) zwei Sprachmodelle aus. Das kleinere (schnellere) dient als Draft Model. Während der Token-Generierung macht das Draft Model Vorschläge für die folgenden Token. Das größere, qualitativ bessere Modell überprüft anschließend eine Sequenz mehrerer vorgeschlagener Token auf einmal. Im Idealfall wird die ganze Sequenz akzeptiert. Der Geschwindigkeitsvorteil ergibt sich durch die parallele Verifizierung eines ganzen Token-Blocks. Dazu sind weniger Speicher-Transfers vom VRAM in die GPU notwendig, als wenn jedes Token für sich generiert wird. (Die Token-Generierung wird durch zwei Faktoren limitiert: die Rechenleistung der GPU und die Speicherbandbreite vom VRAM in die GPU-Cores. Speculative Decoding setzt beim zweiten Punkt ein, der oft der limitierende Faktor ist.) In der Praxis funktioniert das nur mäßig gut: Zum einen ist es schwierig, ein geeignetes Draft Model zu finden. Es muss aus der gleichen »Familie« stammen, aber deutlich kleiner sein, idealerweise etwa um den Faktor zehn. Zum anderen funktioniert Speculative Decoding für Dense Models besser als für Mixture of Experts Models (MoE). Das Problem bei MoE besteht darin, dass bei jedem Token andere »Experten« zum Einsatz kommen können, was den Geschwindigkeitsvorteil von Speculative Decoding teilweise zunichtemacht. Kleinere MoE-Modelle für den Draft-Einsatz haben zudem oft eine andere Experten-Aufteilung, was die Acceptance Rate verringert. Multi-Token Prediction (MTP) greift die Idee des Speculative Decoding auf. Der entscheidende Unterschied besteht darin, dass ein Modell ausreicht. Ein in das Modell integrierter Layer ist dafür zuständig, rasch ein paar Tokens (üblicherweise 2 bis 4) vorherzusagen. Das Gesamtmodell überprüft dann alle Token auf einmal, was nur unwesentlich mehr Zeit kostet, als ein Token zu berechnen. MTP erspart damit das umständliche Handling mit zwei Modellen. Speculative Decoding und Multi-Token Prediction sind mit keinerlei Qualitätsverlust verbunden! Es werden exakt die gleichen Ergebnisse erzielt, weil jede Token-Sequenz vollständig kontrolliert und bei Abweichungen verworfen wird. Werfen Sie diesbezüglich einen Blick in das Video von Donata Capitella, das diesen Umstand anschaulich erklärt. Für den erzielten Geschwindigkeitsgewinn ist der Prozentsatz der akzeptierten Draft Tokens entscheidend. Dieser variiert je Aufgabenstellung: Bei kreativem Text ist die Akzeptanzrate nur mittelmäßig, bei Code hingegen deutlich höher — ganz einfach deswegen, weil Code strengen Regeln folgt und weniger Spielraum als menschliche Sprachen bietet. Leider ist auch MTP mit Nachteilen verbunden: Das Modell muss für MTP konzipiert sein. MTP muss schon beim Training berücksichtigt werden. Das Modell benötigt einen zusätzlichen Layer für die Token Prediction. Aktuell gibt es nur eine einzige »freie« Modellfamilie mit MTP, nämlich Qwen 3.6 und dessen Variante Qwopus. Gemma-4-Modelle sollten demnächst folgen. In Zukunft wird MTP wohl zu einem Standard-Feature für freie Modelle. Natürlich muss auch die Software MTP unterstützen. Weil viele Programme intern llama.cpp verwenden, wird MTP rasch weite Verbreitung finden. Schließlich teilt sich MTP einen Nachteil mit Speculative Decoding: Es funktioniert bei herkömmlichen Dense-Modellen besser als bei MoE-Modellen (Mixture of Experts). Die ohnedies schon schnellen MoE-Modelle werden also nur geringfügig schneller oder, wie bei einigen meiner Tests, sogar langsamer. Bei den Dense-Modellen ist dagegen eine spürbare Verbesserung zu bemerken. Bei meinen Tests ca. +65%, bei einigen Benchmarks im Internet bis zu +100%, also eine Verdoppelung der Output-Token-Rate. MTP ändert nichts an der Input-Verarbeitung (dem Prompt Processing, pp). Schneller wird nur der Output (die Token Generation, tg). Dense versus Mixture of Experts (MoE): MoE ist schneller, kann aber qualitativ bei gleicher Modellgröße nicht ganz mithalten. Während bei Dense-Modellen immer alle Parameter aktiv sind, nutzen MoE-Modelle nur wenige, stets wechselnde »Experten«, also Subsets mit viel weniger Parametern. Das spart Zeit, aber kein »Experte« ist so gut wie das volle Modell. Dementsprechend sinkt die Qualität der Antworten, nicht massiv, aber spürbar.) Praktische Erfahrungen Ich habe MTP mit LM Studio 0.4.14 auf meinem Framework Desktop ausprobiert (AMD Ryzen Max 395 CPU/GPU). Mein Mini-Benchmarktests lautete: »Explain Python dictionaries«. Die getesteten Modelle denken über diese Frage eine Weile nach und produzieren dann einen mehrseitigen, qualitativ sehr hochwertigen Text mit eingebauten Code-Schnipseln. <img loading="lazy" decoding="async" src="https://kofler.info/wp-content/uploads/lmstudio-mtp.png" alt="" width="1920" height="1229" class="size-full wp-image-9602" srcset="https://kofler.info/wp-content/uploads/lmstudio-mtp.png 1920w, https://kofler.info/wp-content/uploads/lmstudio-mtp-850x544.png 850w, https://kofler.info/wp-content/uploads/lmstudio-mtp-1280x819.png 1280w, https://kofler.info/wp-content/uploads/lmstudio-mtp-768x492.png 768w, https://kofler.info/wp-content/uploads/lmstudio-mtp-1536x983.png 1536w" sizes="auto, (max-width: 1920px) 100vw, 1920px" /> LM Studio mit dem Modell Qwen 3.6 und Multi-Token Prediction (MTP) Ich habe alle Tests mit einem Kontextfenster von 128.000 Token ausgeführt. Bei den MTP-Modellen habe ich die Einstellung MTP Max Tokens = 3 verwendet, also immer drei Tokens auf einmal erzeugt. Alle getesteten Modelle weisen eine 4-Bit-Quantisierung auf (Ausnahme: das APEX-Modell, siehe unten). Als Backend kommt llama.cpp mit Vulkan zum Einsatz. Draft Token Modell MoE APEX MTP Output (tg) Acceptance ----------------- ---- ---- ---- ------------ ------------------ qwen-3.6-27b nein nein nein 12,3 Token/s qwen-3.6-27b-mtp nein nein ja 20,1 Token/s 66,3 % qwopus-3.6-27b-v2-mtp nein nein ja 19,0 Token/s 63,7 % qwen-3.6-35b-a3b ja nein nein 69,7 Token/s qwen-3.6-35b-a3b-mtp ja nein ja 67,1 Token/s 66,6 % qwen-3.6-35b-a3b-apex-mtp ja ja ja 71,5 Token/s 63,3 % qwopus-3.6-35b-a3b-mtp ja nein ja 74,2 Token/s 68,2 % Professionellere Benchmark-Tests hat Donata Capitella durchgeführt (siehe die ersten zwei Links in den Übersicht der Quellen am Ende des Artikels). Interessanterweise ist dort auch bei MoE-Modellen ein spürbarer Geschwindigkeitszuwachs von etwa 30% zu sehen, den ich bei meinen Tests aber nicht nachvollziehen kann. Qwopus-Modelle Die neuen Qwopus-Modelle basieren auf Qwen-Modellen, erhalten aber ein zusätzliches Fine-Tuning mit Claude Opus. Dieses soll den Nachdenkprozess beschleunigen und eine bessere Antwortqualität mit sich bringen. Die erste Versprechung trifft definitiv zu, aber ich bin nicht in der Lage, die Qualität des Modells im Detail zu beurteilen. Subjektiv hatte ich den Eindruck, dass die Unterschiede zu den Qwen-Originalen gering sind. Zum Denkprozess: Beim Prompt »write a Sudoku solver in Python« denkt qwen-3.6-27b-mtp ca. 1:30 Minuten nach, qwopus-3.6-27b-v2-mtp aber ca. nur 1:00 Minuten. (Die Denkzeit hat eine relativ starke Varianz, weswegen hier genaue Angaben sinnlos sind.) Die resultierende Antwort samt Code ist mehr oder weniger gleichwertig (Backtracking-Algorithmus). APEX Quantisierung Die Verkleinerung von Modellen bei möglichst geringen Qualitätsverlust ist zu einer eigenen KI-Disziplin geworden. Die Grundidee besteht darin, Milliarden von Parametern (also eigentlich Fließkommazahlen) mit möglichst wenigen Bits darzustellen, ohne dass die Qualität der Ergebnisse allzu sehr leidet. Der geringere Platzbedarf von Modellen ist insbesondere dann wichtig, wenn der Speicher (VRAM) limitiert ist. Mit einer geschickten Quantisierung läuft ein Modell vielleicht gerade noch auf einer GPU mit 16 GiB VRAM. Vor ein paar Monaten machte Google mit dem neuen Turbo-Quant-Verfahren Furore. Bei der Recherche für diesen Artikel bin ich nun auf das neue Verfahren Adaptive Precision for EXpert Models (APEX) gestoßen. Das von Local AI entwickelte Verfahren ist speziell für MoE-Modelle optimiert und kompatibel zu aktuellen llama.cpp-Versionen. Die Grundidee besteht darin, dass für jede Parametergruppe eine andere, für den Wertebereich und die Wichtigkeit angepasste Quantisierung verwendet wird. Insofern ist eine klare Bit-Angabe (4 Bit pro Parameter) unmöglich. Technische Details und Benchmarks finden Sie auf der GitHub-Projektseite. Local AI arbeitet daran, Modelle lokal auf Smartphones auszuführen; da ist die möglichst platzsparende Darstellung natürlich wichtig. Konkret sind APEX-Modelle zum Teil wirklich erheblich kleiner als vergleichbare Modelle mit Q4-Quantisierung, wie sie bei der lokalen Ausführung von Modellen üblich ist. Die folgende Tabelle zeigt lauter Qwen-3.6-Modelle mit jeweils 35 Milliarden Parameter. Das APEX-MTP-Modell benötigt nur halb so viel Platz wie das MTP-Modell mit einer herkömmlichen Q4-Quantisierung. <img loading="lazy" decoding="async" src="https://kofler.info/wp-content/uploads/lmstudio-mtp-apex.png" alt="" width="1920" height="757" class="size-full wp-image-9614" srcset="https://kofler.info/wp-content/uploads/lmstudio-mtp-apex.png 1920w, https://kofler.info/wp-content/uploads/lmstudio-mtp-apex-850x335.png 850w, https://kofler.info/wp-content/uploads/lmstudio-mtp-apex-1280x505.png 1280w, https://kofler.info/wp-content/uploads/lmstudio-mtp-apex-768x303.png 768w, https://kofler.info/wp-content/uploads/lmstudio-mtp-apex-1536x606.png 1536w" sizes="auto, (max-width: 1920px) 100vw, 1920px" /> Überblick der heruntergeladenen Modelle in LM Studio Leider verrät die Huggingface-Seite des Modells nicht, welche Variante der APEX-Quantisierung verwendet wurde. Es existieren verschiedene Qualitätsstufen, z.B. Quality, Balanced, Compact und Mini. Ich würde vermuten, das Modell ist eher bei Mini als bei Quality angesiedelt. Modell Quantisierung Größe (Disk) ------------------------ ------------- ------------ qwen-3.6-35b-a3b Q4_K_M 22,0 GB qwen-3.6-35b-a3b-mtp Q4_K_S 23,0 GB qwen-3.6-35b-a3b-apex-mtp APEX 11,7 GB (!) Bei der Ausführung des Modells waren für mich keine nennenswerten Unterschiede erkennbar, weder in der Geschwindigkeit noch qualitativ. Aber nochmals: Das sind subjektive Feststellungen anhand einiger Tests, keine objektiven Benchmark-Tests. Dazu fehlt mir ganz einfach die Zeit. Quellen/Links https://www.youtube.com/watch?v=MI0Pm1d6YF4 (gutes Video von Donata Capitella) https://kyuz0.github.io/amd-strix-halo-toolboxes/mtp.html (Benchmarks von Donata Capitella) https://sebastianraschka.com/llm-architecture-gallery/mtp/ https://github.com/ggml-org/llama.cpp/pull/22673 (MTP für llama.cpp) https://lmstudio.ai/changelog/lmstudio-v0.4.14 (LM Studio Changelog) https://github.com/localai-org/apex-quant Ausgewählte Modelle mit MTP und/oder APEX https://huggingface.co/unsloth/Qwen3.6-35B-A3B-MTP-GGUF (Qwen MTP) https://huggingface.co/Jackrong/Qwopus3.6-27B-v2-MTP-GGUF (Qwopus MTP) https://huggingface.co/Jackrong/Qwopus3.6-35B-A3B-v1-MTP-GGUF (ebenso) https://huggingface.co/mudler/Qwen3.6-35B-A3B-APEX-MTP-GGUF (APEX) Technisch/Wissenschaftliche Grundlagen https://arxiv.org/abs/2211.17192 (Speculative Decoding) https://arxiv.org/abs/2404.19737 (MTP) https://arxiv.org/abs/2509.18362v1 (FastMTP) https://arxiv.org/abs/2412.19437 (MTP in DeepSeek-Modellen) https://blog.google/innovation-and-ai/technology/developers-tools/multi-token-prediction-gemma-4/ (MTP in Gemma-Modellen)