1.3 Text Processing Lab

In diesem Lab werden Programme, Hilfsmittel und Workflows vorgestellt die bei der Verarbeitung von Text hilfreich sind.

Inhalt

Vorbereitung

Um die folgenden Beispiele anschaulich zu machen, erstellen wir erst eine Datei mit einer Textzeile die wir später nach belieben bearbeiten können. Die Zeile enthält sowohl Buchstaben als auch Zeichen und ein Tab-Steuerzeichen. Ein Tab kann auf der Shell mittels CTRL-V + Tab eingefügt werden. Der Einfachheit halber ist die Sampledatei bereits in diesem Lab enthalten.

Erstellen einer Datei mit Text

1
2
3
$ echo "The quick brown; fox jumps over the lazy	dog" > sample.txt
$ cat -v sample.txt
The quick brown; fox jumps over the lazy	dog

Wir erstellen die Textdatei und überprüfen mit cat -v deren Inhalt. Die Option -v weist cat dazu an auch Zeichen auszugeben die normalerweise versteckt wären.

cut

Wie der Name schon andeutet wird cut verwendet um eine Textzeile in ihre Bestandteile zu zerlegen. Als erstes wollen wir aus dem Text an einer bestimmten Stelle ein Zeichen extrahieren. Dazu verwenden wir die Option -c.

Ausgeben ausgewählter Zeichen aus einem String

1
2
3
4
5
6
$ cut -c 5 sample.txt
q
$ cut -c 5,6 sample.txt
qu
$ cut -c 5-10 sample.txt
quick

Wollen wir zusammenhängende Textstellen aus dem String herausschneiden können wir dies über die Option -f realisieren. Diese Option spezifiziert ein Feld. Ein Feld stellt eine nicht unterbrochene Aneinanderreihung von Zeichen dar.

Ausgeben des zweiten Feldes des Strings

1
2
$ cut -f 2 sample.txt
dog

Hier stellt sich natürlich die Frage wieso nun gerade “dog” ausgegeben wird. Wie bereits gesagt besteht ein Feld aus einer Aneinanderreihung von Zeichen die nicht unterbrochen werden. Der einzige Unterbruch im Text stellt das Tab-Steuerzeichen dar. Dies ist das Standardtrennzeichen. Natürlich können wir dieses Trennzeichen aber selbst spezifizieren. Dies geht über die Option -d.

Ausgeben des zweiten Feldes des Strings mit spezifizierung des Trennzeichens

1
2
$ cut -f 2 -d ";" sample.txt
fox jumps over the lazy	dog

paste

Für diese Übung erstellen wir ein neues Textfile welches auch Zeilenumbrüche enthält.

Erstellen einer neuen Textdatei mit Zeilenumbrüchen

1
$ echo -e "the\nquick\nbrown\nfox" > sample2.txt

Um die Zeilenumbrüche darzustellen können wir echo mit der Option -e aufrufen welche Bash-Escapesequenzen zulässt. Eine Auflistung aller möglichen Escapesequenzen finden wir natürlich in der Manpage. Um zu dieser Liste zu gelangen rufen wir die Manpage mittels man bash auf und Suchen nach dem Eintrag “PROMPTING”. Gesucht wird über / gefolgt von der Eingabe des Suchbegriffes.

Nun da wir unser Textfile haben versuchen wir herauszufinden was paste genau damit macht.

Ausprobieren der verschiedenen Optionen von paste

1
2
3
4
5
6
7
$ paste sample2.txt
the
quick
brown
fox
$ paste -s sample2.txt
the	quick	brown	fox

Wir sehen dass paste ohne erweiterte Optionen, analog cat, einfach den Text der Datei ausgibt. Die interessante Option ist -s sie setzt alle einzelnen Zeilen aneinander und trennt sie mit dem Standardtrennzeichen Tab. Natürlich können wir auch an dieser Stelle wieder das Standardtrennzeichen überschreiben.

Ausgeben der einzelnen Zeilen getrennt durch ein Space

1
2
$ paste -s -d " " sample2.txt
the quick brown fox

Das Programm head wird dazu verwendet wenn wir nur einen gewissen Teil eines sehr grossen Textes ausgeben möchten. Dies kann zum Beispiel ein Logfile wie /var/log/syslog sein. Ohne weitere Option gibt head nur die ersten 10 Zeilen der Datei aus. Über die Option -n kann die Anzahl ausgegebener Zeilen angepasst werden.

Verwendung von head mit und ohne Optionen

1
2
$ head /var/log/syslog
$ head -n 15 /var/log/syslog

Die weiteren Optionen können der Manpage entnommen werden.

tail

Das Programm tail ist ziemlich ähnlich wie head, jedoch gibt es den Schluss der gewählten Datei aus. Dies ist sehr hilfreich zum Betrachen von Logfiles, da die neusten Ereignisse immer unten angefügt werden. Auch hier werden ohne weitere Option die letzten 10 Zeilen der Datei ausgegeben.

Verwendung von tail analog zu head

1
2
$ tail /var/log/syslog
$ tail -n 15 /var/log/syslog

tail verfügt im Gegensatz zu head aber über die Option “follow”. Wird diese Option mitgegeben wird die Datei laufend gelesen und es werden Änderungen sofort ausgegeben.

Verwendung von tail’s follow Option

1
$ tail -f /var/log/syslog

Um das ganze ein wenig anschaulicher zu gestalten, können wir folgendes verwenden. Wir benötigen dazu zwei Terminals. Im ersten wird folgender Befehl ausgeführt.

Schlaufe die jede Sekunde einen Eintrag in ein Logfile schreibt

1
$ while true; do date +%s >> time.log; sleep 1; done

Obige Zeile ist villeicht ein wenig vorgegriffen. Sie weist die Shell dazu an zwei Befehle in einer Endlosschleife auszuführen. Hier:

  • date +%s >> time.log
    • Gibt den aktuellen Unix Timestamp (die Anzahl Sekunden seit dem 01.01.1970) aus.
  • sleep1
    • Veranlasst die Shell eine Sekunde lang zu warten.

Im zweiten Terminal betrachten wir nun die Datei mittels tail und aktiviertem Follow.

Ausgabe von tail mit aktivierter Followoption

1
2
3
4
5
6
7
$ tail -f time.log
1588192983
1588192984
1588192985
1588192986
1588192987
...

expand und unexpand

Im Umgang mit Programmcode (speziell Python) ist es dringend nötig sich entweder für Tabs oder für Spaces als Trennzeichen zu entscheiden. Denn ein Gemisch aus Beiden vertragen Interpreter in der Regel nur sehr schlecht.

Ganz abgesehen vom offensichtlichen Glaubenskrieg zwischen den beiden Optionen gibt es für beide Varianten gute Argumente. Da hier keine Indoktrinierung stattfinden soll, sei die lesende Person ermutigt sich über eine Googlesuche mit der Thematik zu befassen und es wird auf eine Empfehlung verzichtet. *hust* spaces *husthust*. ;)

Ganz abgesehen davon stehn uns mit den Programmen expand und unexpand zwei Werkzeuge zur Verfügung welche beim Ersetzen von Tabs respektive Gruppen von Spaces helfen. Verdeutlichen wir uns das anhand unseres sample.txt.

Verwenden von expand um Tabs durch Spaces zu ersetzen

1
2
3
4
$ expand sample.txt
The quick brown; fox jumps over the lazy        dog
$ expand -t 4 sample.txt
The quick brown; fox jumps over the lazy     dog

Wir sehen zusätzlich dass wir über die Option -t angeben können durch wieviele Spaces ein Tab ersetzt werden soll.

Das Programm unexpand macht nun wie der Name schon andeutet genau das Gegenteil. Auch hier lässt sich mittels -t wieder angeben wie viele Spaces ein Tab werden sollen.

Verwenden von unexpand um n Spaces durch Tabs zu ersetzen

1
2
$ expand sample.txt > expanded_sample.txt
$ unexpand -a -t 8 expanded_sample.txt

sort

Möchte man eine Textdatei alphabetisch sortieren so bietet sort die gewünschte Funktionalität. Betrachten wir folgende Liste von Bierstilen.

Durcheinandergeratene Liste mit Bierstilen

1
2
3
4
5
6
7
8
9
$ echo -e "Gose\nPorter\nAmber\nSaison\nAle\nStout\nHefeweizen" > beers.list
$ cat beers.list
Gose
Porter
Amber
Saison
Ale
Stout
Hefeweizen

Möchten wir die Biere alphabetisch sortieren können wir dies mittels sort machen.

Alphabetisch geordnete Liste mit Bierstilen

1
2
3
4
5
6
7
8
$ sort beers.list
Ale
Amber
Gose
Hefeweizen
Porter
Saison
Stout

Natürlich geht das Ganze auch in umgekehrter Reihenfolge.

Umgekehrte, alphabetisch geordnete Liste mit Bierstilen*

1
2
3
4
5
6
7
8
$ sort -r beers.list
Stout
Saison
Porter
Hefeweizen
Gose
Amber
Ale

Paradoxerweise besitzt sort auch die Möglichkeit eine neue, zufällige Reihenfolge zu erstellen. Dies über die Option -R respektive --random-sort. Will man Zahlen sortieren, zum Beispiel Dateigrössen, hilft das -h Flag. Für weitere lustige Sortieroptionen sei an die Manpage verwiesen.

tr

Translate oder tr hilft dabei Buchstaben oder ganze Buchstabenfolgen durch andere zu ersetzen. Der einfachste Anwendungsfall ist es beispielsweise alle kleinen durch grosse Buchstaben zu ersetzen.

Verwendung von Translate zum ersetzen von Buchstaben

1
2
3
$ tr a-z A-Z
hello puzzle
HELLO PUZZLE

Ein weiteres Beispiel ist das Ersetzen von Spaces. Betrachten wird folgende Beispiele.

Verwendung von Translate zum Ersetzen von Spaces

1
2
3
4
5
6
7
$ echo "My UID is $UID" | tr " " "\n"
My
UID
is
1000
$ echo "my sentence     has    so many    spaces" | tr -s " "
my sentence has so many spaces

Im ersten Aufruf wird ein Space jeweils durch ein Zeilenumbruch ersetzt. Der zweite Aufruf bedient sich tr’s Squeeze-Repeats Funktion. Damit werden sich widerholdene Aufrufe des spezifizierten Zeichens durch ein einzelnes Zeichen ersetzt.

uniq

Betrachten wir wieder einmal unsere Liste mit Bierstilen.

Durcheinandergeratene Liste mit Bierstilen und teils doppelten Einträgen

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ echo -e "Gose\nGose\nPorter\nPorter\nAmber\nAmber\nSaison\nAle\nAle\nStout\nStout\nHefeweizen" > beers.list
$ cat beers.list
Gose
Gose
Porter
Porter
Amber
Amber
Saison
Ale
Ale
Stout
Stout
Hefeweizen

Das Chaos lässt sich mittels uniq einfach beseitigen. Das Programm liest die Liste und gibt alle Werte jeweils nur einmal aus, sollten sie doppelt oder mehrfach vorkommen.

Durch uniq gefilterte Bierstilliste und Ausgabe der Anzahl Einträge

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
$ uniq beers.list
Gose
Porter
Amber
Saison
Ale
Stout
Hefeweizen
$ uniq -c beers.list
2 Gose
2 Porter
2 Amber
1 Saison
2 Ale
2 Stout
1 Hefeweizen

Nun muss man aber aufpassen. uniq wird Duplikate nur entfernen wenn diese aufeindanderfolgend auftauchen! Daher sollte man uniq häufig mit sort kombinieren um auch sicher alle Duplikate zu enfernen.

Kombination von sort und uniq

1
2
3
4
5
6
7
8
$ sort beers.list | uniq
Ale
Amber
Gose
Hefeweizen
Porter
Saison
Stout

wc und nl

Das Programm wc steht für Word Count. Es zählt die Anzahl Wörter die in einem Text vorkommen. Mit den zusätzlichen Optionen c,m,l kann man sich aber auch die Anzahl Zeichen, Anzahl Buchstaben oder Anzahl Zeilen ausgeben lassen.

Wie viele Useraccounts existieren auf meinem System?

1
2
$ wc -l /etc/passwd
30

Ein weiteres Programm das noch ein wenig einfacher ist, ist nl. Es Printet ein File und präfixt die Zeilennummern.

Verwendung von nl zum Anzeigen der Zeilennummern

1
2
3
4
5
$ nl sample2.txt
1 the
2 quick
3 brown
4 fox

grep

Zum Schluss dieses Labs sehen wir uns noch das wahrscheinlich am Meisten verwendete Textbearbeitungsprogramm der Welt an. Der Name grep leitet sich von seiner Verwendung als Regular Expression Interpreter ab. Und Zwar vom Ausdruck g/re/p. Was soviel bedeutet wie global search / regular expression / print

grep ist enorm vielseitig und im Bezug auf Textsuche sehr mächtig. Da dieses Lab sich aber nur mit den Basics befasst sei der Funktionsumfang auf das Suchen von Patterns gekürzt.

Verwendung von grep zur Suche eines Wortes in einem Text

1
2
$ grep fox sample.txt
The quick brown; fox jumps over the lazy	dog

Obiger Aufruf ist die denkbar einfachste Verwendung von grep. Damit wird das angegebene Textfile nach dem angegeben Muster durchsucht. In der Ausgabe wird jede gefundene Instanz des Musters hervorgehoben. Dies ist besonders in grossen Dateien praktisch.

Verwendung von grep zur Case insensitiven Suche nach dem Wort User im Environment

1
2
3
4
5
6
$ env | grep -i user
I3SOCK=/run/user/1000/i3/ipc-socket.1723
XDG_SESSION_CLASS=user
USER=tux
XDG_RUNTIME_DIR=/run/user/1000
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus

Obiges Beispiel nutzt die Option -i von grep zur Suche nach dem Wort “User”. Durch -i spielt Gross/Kleinschreibung keine Rolle. Hier sehen wir auch schon wie grep auf den Output von env angewendet wird. Das Durchsuchen von Output ist ein sehr häufiger Verwendungszweck für grep.

Als kleiner Bonus sehen wir uns noch folgendes Beispiel an, welches oft hilft wenn man in einem Projekt vergessen hat wo man die gesuchte Information aufgeschrieben hat, oder das Chaos eines Kollegen durchsuchen muss.

Durchsuchen von beliebig vielen Dateien

1
2
$ grep -irn "biertrinken"
somelist.txt:200:termin biertrinken am 26.04.2020 um 16:30

Die Kombination von -irn (ausgeschrieben -i -r -n) veranlasst grep dazu im aktuellen Ordner in allen Unterordnern alle Dateien (-r für rekursiv) nach dem Case insensitiven (-i) Suchbegriff zu durchsuchen und gibt die Datei mit der Zeilennummer aus (-n) in welchem der Suchbegriff gefunden wurde. Mit dieser Methode kann man sehr schnell Sachen in einem grossen Haufen von Daten wiederfinden. Wir sehen nun im obigen Beispiel auf den ersten Blick, dass der gesuchte Begriff in der Datei somelists.txt auf der Zeile 200 auftaucht.

Zuletzt geändert July 17, 2025: minor revisions to sys-labs (cac04ae)