Makros helfen dabei, sich wiederholende Vorgänge zu automatisieren. Vim verwendet dazu ein spannendes Konzept, das einen genaueren Blick darauf lohnt.
Bei langjährigen Linux-Nutzern bilden sich unvermeidlich Präferenzen bei der Wahl der Editoren zum Bearbeiten von Text und Programmcode heraus: Der eine bevorzugt Vim, der andere setzt lieber Emacs [1] ein. Beide Editoren besitzen ihre Eigenheiten. Ein effektives Nutzen der Werkzeuge erfordert neben Recherche und Geduld die Akzeptanz, sich dabei freiwillig Schrammen zu holen. All das ist mitunter etwas mühselig und setzt voraus, sich in die Gedankenwelt der Entwickler hineinzuversetzen, um zu verstehen, wie sie die Implementierungen konzipiert haben. Ungeachtet dessen tragen beide Werkzeuge erheblich dazu bei, effektiv zu arbeiten.
Im vorigen Teil [2] dieser Artikelserie lag der Fokus auf dem Grundlagenwissen zu regulären Ausdrücken. Wir beleuchteten dazu die verfügbaren Regex-Konzepte und insbesondere die verwendeten Regex-Dialekte und Besonderheiten innerhalb der beiden Texteditoren. Damit ist das Handlungsspektrum allerdings noch nicht ausgeschöpft: Nun sehen wir uns an, wie die Automatisierung mittels Makros in Vim funktioniert; in Emacs dient dazu Macroscript [3]. Aufgrund der Komplexität geht es hier erst einmal nur um Makros, Macroscript folgt im nächsten Teil dieser Serie.
Anhand eines Praxisbeispiels kombinieren wir die beiden Konzepte Regex und Makro miteinander: Aus einer einfachen, mittels Kommas separierten Liste aus E-Mail-Adressen erzeugen wir eine neue Tabelle. Sie enthält die drei Spalten Vorname, Nachname und E-Mail-Adresse. Diese Tabelle reichen wir für ein Massen-Mailing an Thunderbird [4] weiter. Jede E-Mail verfügt dann über eine persönliche Anrede.
Damit sich das gewählte Vorgehen leichter einordnen lässt, setzen wir unseren Lösungsweg in den Kontext der Werkzeuge für die Kommandozeile. Das erlaubt einen Vergleich und eine Auswahl, welcher Lösungsweg für den konkreten Anwendungsfall und das persönliche Setup am besten passt.
Regex und E-Mails
Ohne konkretes Anwendungsbeispiel fällt es schwer, Makros zu verstehen. Als Ausgangspunkt für die folgenden Betrachtungen dient eine Textdatei mit E-Mail-Adressen, die wir mithilfe eines regulären Ausdrucks in ein anderes Format umwandeln. Als Datenbasis kommen die Kontaktdaten [5] der kanadischen Parlamentsabgeordneten der Provinz Alberta mit Stand vom 3. Oktober 2023 zum Einsatz (Listing 1).
Listing 1
Datenbasis (Auszug)
shuvaloy.majumdar@parl.gc.ca, Ziad.aboultaif@parl.gc.ca, john.barlow@parl.gc.ca, blaine.calkins@parl.gc.ca, michael.cooper@parl.gc.ca, [...]
Das Ziel besteht wie erwähnt darin, eine Tabelle mit drei Spalten zu erhalten. Für die ersten fünf Einträge sieht sie aus wie in Listing 2.
Listing 2
Tabelle für Thunderbird (Auszug)
VORNAME,NAME,EMAIL Shuvaloy,Majumdar,shuvaloy.majumdar@parl.gc.ca Ziad,Aboultaif,Ziad.aboultaif@parl.gc.ca John,Barlow,john.barlow@parl.gc.ca Blaine,Calkins,blaine.calkins@parl.gc.ca Michael,Cooper,michael.cooper@parl.gc.ca [...]
Für Thunderbird steckt dahinter eine CSV-Datei mit Kommas als Spaltentrenner. Der reguläre Ausdruck leitet aus der ersten Zeile die Spaltentitel ab und erlaubt in der E-Mail Markierungen für Platzhalter, beispielsweise {{VORNAME}} für den jeweiligen Wert aus der dazugehörigen Spalte und {{EMAIL}} für die E-Mail-Adresse des Empfängers aus der dritten Spalte der Tabelle.
Zunächst gilt es, aus den Originaldaten die Tabelle zu erzeugen. Um den Vor- und Familiennamen jedes Empfängers abzuleiten, hilft uns hier das übereinstimmende Format aller E-Mail-Adressen der Liste (Vorname.Name@Domain). Relevant sind für uns lediglich Vor- und Nachname, jeweils mit groß geschriebenem ersten Buchstaben. Der Text nach dem @-Zeichen interessiert uns weniger, weshalb wir diese Teilzeichenkette bewusst unscharf spezifizieren. Das reduziert den Aufwand für das Formulieren und Auswerten des Regex.
Nun müssen alle Bestandteile der Namen richtig aus den Daten ausgelesen und gegebenenfalls noch korrigiert werden. Nach einem sorgfältigen Blick auf die Daten fällt auf, dass der Inhalt der Namensliste nicht ganz einheitlich ausfällt: Manche Namen bestehen ausschließlich aus Kleinbuchstaben, andere dagegen liegen gemischt vor. Im Endergebnis sollen alle Vor- und Nachnamen mit einem großen Anfangsbuchstaben beginnen, auf den danach nur noch Kleinbuchstaben folgen.
Anspruchsvoller wird es, wenn mehrere Vornamen angegeben sind. So gibt es Abgeordnete mit den Vornamen Marie-Claire und Jasraj Sing. Lösen lässt sich das durch manuelles Nachbearbeiten oder durch einen zusätzlichen Regex. Als herausfordernd erweisen sich dabei Bindestriche – nicht jeder Doppelname enthält tatsächlich einen. Sich dabei auf geschicktes Raten einzustellen, hilft ungemein. Wir stellen diesen Sonderfall hier zurück.
Umsetzung
Das anvisierte Ziel direkt im Texteditor zu erreichen, gehört wohl nicht unbedingt zu den naheliegenden Lösungswegen. Schließlich verfügt ein Linux-System über einen großen Werkzeugkasten mit zahlreichen spezialisierten Hilfsmitteln, die sich clever einsetzen lassen. Daher werfen wir zunächst einen Blick auf eine Lösung für die Kommandozeile [6]. Wir bedienen uns der vier Werkzeuge Cut, Echo, Tr und Sed, die in mehreren Schleifen Verwendung finden, um die Ausgangsdaten zu bearbeiten. Einen ähnlichen Regex benutzen wir anschließend beim jeweiligen Editor. Über die Umsetzung mit Awk anstatt Sed informiert der Kasten “Exkurs: Umwandlung mittels Awk”.
Exkurs: Umwandlung mittels Awk
Statt des Stream-Editoren Sed können Sie auch Awk [7] verwenden. Das Tool stellt dazu die drei eingebauten Funktionen substr(), toupper() und tolower() bereit [8]. Dabei extrahiert das Kommando substr() eine Teilzeichenkette. Die Funktionen toupper() und tolower() wandeln Zeichen in Groß- beziehungsweise Kleinbuchstaben um. Ein konkretes Anwendungsbeispiel finden Sie in Listing 1.
Listing 3
Awk
capitalize () {
echo $1 | awk '{ print toupper(substr($0,1,1)) tolower(substr($0,2)) }'
}
Im ersten Schritt müssen wir die Adressliste in einzelne Zeilen zerlegen. Dabei greift uns Sed unter die Arme. Wir ersetzen jedes Vorkommen von , durch einen Zeilenumbruch und speichern die Ausgabe in einer Datei namens namensliste:
$ sed -E -n "s/,\s+/\n/gp" maildaten > namensliste
Listing 4 enthält ein Shell-Skript, das als einzigen Parameter eine E-Mail-Adresse in Form einer einzeiligen Zeichenkette entgegennimmt. Daraus extrahiert es Vor- und Nachname und wandelt beide in die gewünschte Schreibweise mit führendem Großbuchstaben um. Als Ergebnis kommt eine Zeile heraus, wie wir sie für die Tabelle aus Listing 2 benötigten. Das Skript besteht aus der Funktion capitalize() (Zeilen 2 bis 7) und einem Hauptteil (ab Zeile 8). Wir kümmern uns erst um den Hauptteil und besprechen danach die Funktion.
Listing 4
extract-email-addresses2.sh
#!/bin/bash
capitalize () {
# transform the 1st letter of a string to uppercase
firstLetter=$(echo $1 | cut -c1 | tr [:lower:] [:upper:])
remainingLetters=$(echo $1 | cut -c2- | tr [:upper:] [:lower:])
echo "$firstLetter$remainingLetters"
}
# output table header
echo "VORNAME,NAME,EMAIL"
# extract firstname, and lastname from email address firstname.lastname@domain
extractedData=$(echo "$1" | sed -E -n 's/^(\w+)\.(\w+)@.+/\1,\2/p')
# uppercase 1st letter of firstname, and lastname
# - extract firstname from email address
firstname=$(echo $extractedData | cut -d "," -f 1)
firstname=$(capitalize $firstname)
# - extract lastname from email address
lastname=$(echo $extractedData | cut -d "," -f 2)
lastname=$(capitalize $lastname)
# output transformed string
echo "$firstname,$lastname,$1"
Zeile 9 enthält die Ausgabe des Tabellenkopfs mit den drei bekannten Spalten. In Zeile 12 kommt zuerst echo zum Einsatz, das den Aufrufparameter ausgibt. Die Ausgabe reichen wir über eine Pipe an Sed weiter. Das verarbeitet diesen Wert mithilfe des Suchmusters s/Muster/Ersetzung/Aktion auf der Basis eines erweiterten Regex (Schalter -E, Zeile 11). Das Muster beginnt am Zeilenanfang (^). Es folgen mindestens ein Zeichen (\w+) für den Vornamen, ein Punkt (\.) als Trennzeichen, wiederum mindestens ein Zeichen (\w+) für den Nachnamen, ein @ als Trennzeichen und darauf schließlich mindestens ein weiteres, beliebiges Zeichen (.+) für die Domain.
Die einfachen Klammern (\w+) sorgen dafür, dass sich Vor- und Nachname später referenzieren lassen, hier mittels \1 und \2 für den ersten und zweiten Suchtreffer. Die Ersetzung des Musters besteht nur aus den beiden Suchtreffern, die wir durch ein Komma voneinander trennen. Als Aktion benutzen wir p für print, was in Kombination mit dem Schalter -n im Aufruf von Sed lediglich die Ersetzung ausgibt. Das Ergebnis des Aufrufs merken wir uns in der lokalen Variable extractedData für eine spätere Weiterverarbeitung.
In den Zeilen 14 und 17 kombinieren wir die Befehle echo und cut. Letzterer liest mittels -f 1 das erste Feld und mittels -f 2 das zweite Feld aus dem Inhalt der zuvor gefüllten lokalen Variablen extractedData aus. Als Trennzeichen fungiert erneut ein Komma, worüber wir Cut mit dem Parameter -d "," informieren.
Anschließend rufen wir in den Zeilen 15 und 21 capitalize() auf, das sich der Groß- und Kleinschreibung des Inhalts der beiden Variablen firstname und lastname annimmt. Die Funktion verarbeitet einen Übergabeparameter, der sich unter der Variablen $1 ansprechen lässt.
In Zeile 4 entnimmt cut mithilfe des Schalters -c1 das erste Zeichen des Inhalts von $1 und reicht es über eine Pipe an tr weiter. Daraufhin wandelt tr einen Kleinbuchstaben in den entsprechenden Großbuchstaben um. Die beiden Angaben [:lower:] (Zeile 4) und [:upper:] (Zeile 5) repräsentieren die jeweiligen Zeichenklassen für Klein- beziehungsweise Großbuchstaben und schließen außerdem Umlaute und Sonderzeichen für den jeweiligen Zeichensatz mit ein. Eine Angabe von [a-z] erweist sich hier als unvollständig. Das Ergebnis der Umwandlung landet in der Variable firstLetter.
Ähnlich gehen wir in Zeile 5 vor, mit dem Unterschied, dass hier cut mittels -c2- alle Zeichen ab Position 2 bis zum Wortende verarbeitet und nachfolgend tr sämtliche Großbuchstaben in Kleinbuchstaben umwandelt. Das Ergebnis findet sich anschließend in der Variable remainingLetters wieder.
In Zeile 6 fügen wir die Inhalte der beiden Variablen zusammen und geben sie mithilfe von echo aus. Somit besitzt die Funktion capitalize() einen Rückgabewert, den dann der aufrufende Programmteil ausliest und verarbeitet. Am Ende erfolgt die Ausgabe der beiden Variablen firstname und lastname mittels echo, wiederum durch ein Komma voneinander getrennt (Zeile 20).
Da das Umwandeln einzelner E-Mail-Adressen nun funktioniert, wenden wir den bestehenden Programmcode auf die komplette Adressliste an, die ja als Textdatei vorliegt.
Die While-Schleife in Listing 5 liest die Textdatei mittels < ein (letzte Zeile) und verarbeitet sie zeilenweise. Die Schleife läuft so lange, wie sich Zeilen in der Datei befinden, also bis zum Dateiende. Jede Zeile – sprich: Adresse – lesen wir mittels read in die Variable line. Der Parameter -r unterbindet in den gelesenen Daten das Escapen von Zeichen per Backslash (\). Die vorletzte Zeile ruft zur Auswertung das Skript aus Listing 4 auf und übergibt als Parameter lediglich die gerade gelesene Zeile.
Listing 5
convert-email-addresses.sh
#!/bin/bash # read text file that contains # one email address per line while read -r line; do bash extract-email-addresses2.sh $line done < $1
Letztlich lassen sich die Skripte zusammenfassen, was dann Listing 6 ergibt. In unserem Fall liegt die E-Mail-Liste in der lokalen Datei emailliste im aktuellen Verzeichnis vor. Basierend auf dem Skript aus Listing 6 ist der Aufruf zum Erzeugen der Datei aus Listing 2 lediglich ein Einzeiler (Listing 7).
Als Nächstes sehen wir uns an, wie sich das Ganze ausschließlich in Vim bewerkstelligen lässt. Die bisherigen Überlegungen zum Regex für die Kommandozeile fließen hier mit ein.
Listing 6
convert-email-addresses2.sh
#!/bin/bash
capitalize () {
# transform the 1st letter of a string to uppercase
firstLetter=$(echo $1 | cut -c1 | tr [:lower:] [:upper:])
remainingLetters=$(echo $1 | cut -c2- | tr [:upper:] [:lower:])
echo "$firstLetter$remainingLetters"
}
# output table header
echo "VORNAME,NAME,EMAIL"
# read one email address per line
sed -E -n "s/,\s+/\n/gp" "$1" | while read -r line
do
# extract firstname, and lastname from
# email address firstname.lastname@domain
extractedData=$(echo "$line" | sed -E -n 's/^(\w+)\.(\w+)@.+/\1,\2/p')
# uppercase 1st letter of firstname, and lastname
# - extract firstname from email address
firstname=$(echo $extractedData | cut -d "," -f 1)
firstname=$(capitalize $firstname)
# - extract lastname from email address
lastname=$(echo $extractedData | cut -d "," -f 2)
lastname=$(capitalize $lastname)
# output transformed string
echo "$firstname,$lastname,$line"
done
Listing 7
Mailmerge-Datei erzeugen
$ bash convert-email-addresses2.sh emailliste > mailing.csv
Äquivalent in Vim
Das Bedienkonzept von Vim ist kommandoorientiert. Zum Zusammenfassen mehrteiliger Arbeitsschritte kennt Vim das Konzept der Makros [9]. Dabei handelt es sich um Tastenfolgen, die man zunächst aufzeichnet und in einem Register ablegt [10]. Vim stellt dazu 26 Register von a bis z bereit, die Sie individuell für die aktuelle Vim-Sitzung füllen.
Dazu wechseln Sie in den Kommandomodus, beispielsweise mit [Esc]+, und drücken [Q]+, um die Aufzeichnung eines Makros zu starten. Dann geben Sie den Namen des Registers an, beispielsweise a. Darauf folgt die abzuspeichernde Kommandofolge. Zu guter Letzt schließt ein Druck auf [Q] die Aufzeichnung ab.
Um beispielsweise das Kommando d$ (alle Zeichen von der aktuellen Cursor-Position bis zum Zeilenende löschen) im Register a abzulegen, tippen Sie die Tastenfolge [Q]+[A]+[D]+[Umschalt]+[**4][Q]. Dabei wird ein eventuell bereits bestehendes Makro überschrieben.
Um nun das Makro zu nutzen, rufen Sie es im Kommandomodus über die Tastenfolge [AltGr]+[Q][A] (@a) auf. Das Löschen bis zum Zeilenende erfolgt in der Zeile, in der sich die Schreibmarke gerade befindet. Um das Makro @a wiederholt aufzurufen, offeriert Vim zwei Möglichkeiten: explizit mittels @a und implizit mittels @@. Bei letzterer Variante sieht der Editor in der Kommandohistorie nach und führt das zuletzt aufgerufene Makro erneut aus.
Welche Makros in den einzelnen Registern liegen, verrät Vim bei Eingabe des Kommandos :registers (kurz :reg). Ergänzen Sie im Aufruf den Namen einer oder mehrerer Register, sehen Sie lediglich deren Inhalt. Abbildung 1 zeigt den Aufruf :reg a für das vorher hinterlegte Makro.
Permanente Makros
Ein angelegtes Makro bleibt zunächst flüchtig, existiert also nur in der laufenden Vim-Sitzung. Beim Beenden des Editors vergisst Vim das Makro wieder. Um es permanent zur Verfügung zu haben, speichern Sie es in der Form let @a='d$' in der Vim-Konfigurationsdatei ab (meist ~/.vim/vimrc). Beim nächsten Start liest der Editor die Konfigurationsdatei, findet das Makro, lädt es ins Register a und stellt es von dort zur Verfügung.
Suchen und Ersetzen
Nun haben Sie das Vorwissen, um ein Makro zum Finden und Umwandeln einer E-Mail-Adresse aus der Liste zu erstellen. Das erfordert eine Vielzahl zusätzlicher Escape-Zeichen, die das Verständnis erschweren. Es gilt, fünf Teilschritte sind zu kombinieren, die Sie dazu als Makros @a bis @e speichern.
Schritt 1 betrifft das Makro @a und zerlegt die Eingabedaten in eine einzige E-Mail-Adresse pro Zeile (Listing 8, erste Zeile). Die Anweisung ersetzt alle Kommas, denen mindestens ein Leerzeichen folgt, durch einen Zeilenumbruch, analog zu Listing 3. Als Besonderheit erwartet Vim hier für den Zeilenumbruch nicht \n, sondern \r. Aus historischen Gründen steht \n in diesem speziellen Fall für den Nullwert.
Listing 8
E-Mail-Adressen zerlegen
let @a='s/,\s\+/\r/g' let @b='1,$s/\(\w\+\)\.\(\w\+\)\(@.\+\)/\1 \2 \3/g' let @c='1,$s/.\+/\L&/g' let @d='1,$s/\(\w\+\)\s\(\w\+\)\s\(.\+\..\+\)/\u\1, \u\2, \1.\2\3/g' let @e='1s/^\(.\+\)$/VORNAME,NAME,EMAIL\r\1/' let @f=':@a | :@b | :@c | :@d | :@e'
Im zweiten Schritt extrahieren Sie Vor- und Familienname sowie die Domain aus der E-Mail-Adresse (Listing 8, zweite Zeile). Alle Komponenten werden hier im Ergebnis mit einem Leerzeichen getrennt. Bei dem Ausdruck 1,$ am Beginn des Makros handelt es sich um eine Bereichsangabe: Vim führt das Makro von der ersten bis einschließlich der letzten Zeile aus. Die Vorgehensweise ähnelt der in Listing 4 und Listing 6.
Im nächsten Schritt (Listing 8, Zeile 3) wandeln Sie alle Zeichen in Kleinbuchstaben um. Die Schreibweise von Muster und Ersetzung ist Vim-spezifisch. Zunächst suchen Sie mittels .\+ alle Zeichen und ersetzen Sie via \L& durch die äquivalenten Kleinbuchstaben. \L steht für Nicht-Kleinbuchstaben und fungiert als Umwandlungsfunktion für den mittels & referenzierten vorherigen Suchtreffer (Back Reference). Die Aktion g steht für “global”, der Ausdruck bearbeitet also alle Worte der Zeichenkette.
In Schritt 4 wandeln Sie für den Vor- und Familiennamen alle Buchstaben am Wortanfang wieder in einen Großbuchstaben um (Listing 8, Zeile 4). Das erledigt die Vim-interne Umwandlungsfunktion \u, die Sie hier mit den Back References \1 und \2 für Vor- beziehungsweise Nachnamen kombinieren. Die E-Mail-Adresse aus \1, \2 und \3 bleibt unverändert in Kleinbuchstaben. Die Aktion g bearbeitet wieder die gesamte Zeile.
Um die Vor- und Nachnamen aus der E-Mail-Liste zu extrahieren, brauchen Sie nun lediglich die vier Makros nacheinander mittels :@a, :@b, :@c und :@d in den betreffenden Zeilen aufzurufen. Das Ergebnis ist identisch zu dem in Listing 2, es fehlt jedoch noch die Titelzeile für die Tabelle. Dazu verwenden Sie einen kleinen Trick: Sie ersetzen die erste Zeile der Datei durch zwei Zeilen. In der ersten steht die gewünschte Titelzeile VORNAME,NAME,EMAIL. Es folgen ein Zeilenumbruch und der bereits bestehenden Inhalt der ersten Zeile (Listing 8, Zeile 5).
Statt für jeden Schritt ein eigenes Makro anzulegen und für jede Zeile manuell auszuführen, wäre es wünschenswert, alle fünf Schritte zu einem einzigen Makro zusammenzufassen. Da Vim auf Ed basiert und somit Aufrufe in dessen Schreibweise ausführen kann, erstellen Sie deshalb ein zusätzliches Makro namens @f (Listing 8, Zeile 6). Wie bei der Bash trennen Sie hier mehrere Kommandos durch eine Pipe (|) voneinander. Ein Aufruf des neuen Makros löst alle zuvor definierten Einzelschritte aus. Damit erhalten Sie dann das gewünschte Ergebnis wie in Listing 2.
Um sich an die Bedeutung der einzelnen Schritte auch später noch erinnern zu können, sollten Sie sie dokumentieren. Da Vim-Makros selbst keine Kommentare erlauben, bleibt nur eine Ergänzung in der Konfigurationsdatei (meist ~/.vim/vimrc). Ein Kommentar beginnt mit einem Anführungszeichen, gefolgt von einem Leerzeichen (Listing 9).
Listing 9
Kommentar
" Makros definieren " - ein Komma gefolgt von mindestens einem " Leerzeichen durch einen Zeilenumbruch " ersetzen; anwenden auf die gesamte Zeile let @a='s/,\s/\+\r/g' [...]
Fazit
Wie Sie gesehen haben, braucht es einige Schritte, um Makros in Vim anzulegen und sinnvoll einzusetzen. Das wird erst mit etwas Übung zur Gewohnheit. In der Kombination mit zusätzlichen Einstellungen und ergänzenden Plugins für Vim [11] entlocken Sie dem Editor Extras für noch mehr Produktivität.
Vims mächtiges Pendant Emacs gilt aufgrund seiner umfangreichen Möglichkeiten vielen als Pseudo-Betriebssystem. Wie Sie darin Makros aktivieren, lesen Sie in der nächsten Folge unserer kleinen Serie. (jlu)
Danksagung
Die Autoren bedanken sich bei Axel Beckert für seine Hilfe und Kritik bei der Vorbereitung des Artikels.
Die Autoren
Frank Hofmann arbeitet zumeist von unterwegs aus Berlin, Genf und Kapstadt als Entwickler, Trainer und Autor. Er gehört zu den Verfassern des Debian-Paketmanagement-Buches [12]. Der gebürtige Kanadier Gerold Rupprecht wohnt seit 30 Jahren in Genf und hat sich auf Finanzsoftware sowie die Evaluierung und die Optimierung IT-bezogener Prozessabläufe spezialisiert. Seit 2000 unterstützt er das GNUstep-Projekt.
Infos
-
“Introduction to Emacs”: https://www.computerhope.com/unix/uemacs.htm
-
Regex in Vim/Emacs (Teil 1): Frank Hofmann, Gerold Rupprecht, “Die Zeichenzauberer”, LU 05/2024, S. 82, https://www.linux-community.de/49980
-
“Keyboard Macros”: https://www.computerhope.com/unix/uemacs.htm#Keyboard-Macros
-
Serien-Mails versenden mit Thunderbird: https://www.brevo.com/de/blog/thunderbird-serienmails-versenden/
-
“Contact your senator”: https://www.4mycanada.com/contact-mp-senator
-
Text auf der Kommandozeile umwandeln: https://linuxreviews.org/HOWTO_convert_text_between_uppercase_and_lowercase_from_the_command_line
-
GNU Awk, https://www.gnu.org/software/gawk/
-
“Awk built-in functions”: https://www.gnu.org/software/gawk/manual/html_node/Built_002din.html
-
“Use Vim macros to automate frequent tasks”: https://www.redhat.com/sysadmin/use-vim-macros
-
Vim-Tipps-Wiki: https://vim.fandom.com/wiki/Macros
-
Vim-Settings: Frank Hofmann, “Angespitzt”, LU 01/2024, S. 40, https://www.linux-community.de/49974
-
Debian-Paketmanagement-Buch: https://dpmb.org





