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.

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

Erstellen einer Datei mit Text

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.

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

Ausgeben ausgewählter Zeichen aus einem String

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.

1
2
$ cut -f 2 sample.txt
dog

Ausgeben des zweiten Feldes des Strings

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.

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

Ausgeben des zweiten Feldes des Strings mit spezifizierung des Trennzeichens

paste

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

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

Erstellen einer neuen Textdatei mit Zeilenumbrüchen

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.

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

Ausprobieren der verschiedenen Optionen von paste

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.

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

Ausgeben der einzelnen Zeilen getrennt durch ein Space

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.

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

Verwendung von head mit und ohne Optionen

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.

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

Verwendung von tail analog zu head

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.

1
$ tail -f /var/log/syslog

Verwendung von tail’s follow Option

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.

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

Schlaufe die jede Sekunde einen Eintrag in ein Logfile schreibt

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.

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

Ausgabe von tail mit aktivierter Followoption

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.

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

Verwenden von expand um Tabs durch Spaces zu ersetzen

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.

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

Verwenden von unexpand um n Spaces durch Tabs zu ersetzen

sort

Möchte man eine Textdatei alphabetisch sortieren so bietet sort die gewünschte Funktionalität. Betrachten wir folgende Liste von 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

Durcheinandergeratene Liste mit Bierstilen

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

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

Alphabetisch geordnete Liste mit Bierstilen

Natürlich geht das Ganze auch in umgekehrter Reihenfolge.

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

Umgekehrte, alphabetisch geordnete Liste mit Bierstilen

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.

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

Verwendung von Translate zum ersetzen von Buchstaben

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

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

Verwendung von Translate zum Ersetzen von 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.

 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

Durcheinandergeratene Liste mit Bierstilen und teils doppelten Einträgen

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.

 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

Durch uniq gefilterte Bierstilliste und Ausgabe der Anzahl Einträge

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.

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

Kombination von sort und uniq

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.

1
2
$ wc -l /etc/passwd
30

Wie viele Useraccounts existieren auf meinem System?

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

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

Verwendung von nl zum Anzeigen der Zeilennummern

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.

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

Verwendung von grep zur Suche eines Wortes in einem Text

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.

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

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

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.

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

Durchsuchen von beliebig vielen Dateien

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 November 8, 2022: convert to hugo, deploy to openshift (856591c)