Aus LinuxUser 06/2001

The Answer Girl (Seite 4)

Mit -d können wir einen Spaltentrenner angeben – leider nur einbuchstabig, aber gut, das können wir später noch mit sed ersetzen. Wichtig ist nur, dass der Delimiter nicht in technik.vok vorkommt. Wie wäre es mit #? Lassen Sie uns nachzählen (engl. count“):

[trish@lillegroenn eng_deu]$  grep -c "#" technik.vok
 0

Genau 0 Mal kommt das Hash-Zeichen („#“) in dieser Wörterbuchdatei vor und eignet sich daher hervorragend als temporärer Spaltentrenner für paste.

Der Rest ist ganz einfach: paste will als Argumente lediglich die beiden Dateien haben, die als erste und weitere Spalte(n) dienen. Nun haben wir zwar keine Dateien, aber die Man Page verrät, dass paste auch mit der Standardeingabe (z. B. aus der Pipe von grep) zufrieden ist, wenn wir statt eines Dateinamens ein - einsetzen.

Eigentlich können wir mit der Standardeingabe STDIN (standard input“) ganz glücklich sein; diese hat nämlich die schöne Eigenschaft, dass eine Zeile aus STDIN verschwindet, sobald sie einmal ausgelesen wurde. Wenn wir paste in einem zugegebenermaßen üblen Hack zweimal STDIN unterschieben, bekommen wir genau den Effekt, den wir wollen: In der ersten Spalte stehen die ungeraden, in der zweiten Spalte die geraden Zeilen:

[trish@lillegroenn eng_deu]$  grep [a-zA-Z] technik.vok | paste -d "#" - -
 Ab-; Abfall#waste
 abfuehren#discharge[…]

Das Hash-Zeichen daraus zu entfernen, ist eine unserer leichtesten Übungen, und das Ergebnis leiten wir gleich in die Datei technik.vok_ um:

[trish@lillegroenn eng_deu]$  grep [a-zA-Z] technik.vok | paste -d "#" - - | sed -e "s/#/ – /" > technik.vok_

Das Ergebnis technik.vok_

Ab-; Abfall – waste
 abfuehren – discharge[…]

… kann sich und damit auch gleich in technik.vok umbenennen lassen.

Damit hätten wir eine genügende Auswahl Wörterbuchdateien (BOOK.VOK, EXERCISE.VOK, eng2ger.vok und technik.vok) am Platz – die Umwandlung der restlichen überlasse ich Ihrem Erfindungsreichtum – und können uns endlich einem kleinen Skript zuwenden, das die Übersetzung auf der Kommandozeile eingegebener Wörter übernimmt.

Einmal umdrehen

Von den hier benutzten vier Vokabeldateien weist BOOK.VOK einen gravierenden Unterschied zu den anderen auf: Der englische Begriff steht links, die deutsche Entsprechung rechts. Da das wb-Skript aus Listing 1 nicht erkennt, dass beispielsweise gestern -- yesterday aus eng2ger.vok und yesterday -- gestern aus BOOK.VOK für unsere Zwecke eine Dublette ist, ist es vermutlich am einfachsten, die Spalten in BOOK.VOK einfach umzudrehen.

Wie bei all den in diesem Answer-Girl vorgestellten Textmodifikationsübungen führen auch hier mehrere Wege zum Ziel; einige sollen an dieser Stelle exemplarisch aufgelistet werden.

Cut & Paste

Mit cut lassen sich Spalten aus einer Textdatei extrahieren, die mit paste wieder – auch in umgekehrter Reihenfolge – zusammengefügt werden können. Den Spaltentrenner geben wir explizit mit der Option -d (delimiter“) an. Leider darf dieser nur ein Zeichen, keine Zeichenkette sein, und das macht das Ganze etwas umständlich:

[trish@lillegroenn eng_deu]$ sed -e "s/ – /%/" BOOK.VOK | cut -d "%" -f 1 > /tmp/BOOK.VOK.1
 [trish@lillegroenn eng_deu]$ sed -e "s/ – /%/" BOOK.VOK | cut -d "%" -f 2 > /tmp/BOOK.VOK.2
 [trish@lillegroenn eng_deu]$ paste -d "%" /tmp/BOOK.VOK.2 /tmp/BOOK.VOK.1 | sed -e "s/%/ – /" > /tmp/BOOK.VOK.paste

In den ersten beiden Zeilen ersetzen wir jeweils den echten Spaltentrenner -- durch das Arbeitstrennzeichen %. Zeile eins holt dann mit cut -f 1 alles heraus, was links neben dem Trennzeichen steht, und schreibt es in die temporäre Datei /tmp/BOOK.VOK.1. Dasselbe geschieht mit der zweiten Spalte (-f 2) rechts vom Trennzeichen in Zeile zwei – die Ausgabe dieser Ausschneideaktion mit cut landet in /tmp/BOOK.VOK.2. Wenn wir paste in der dritten Zeile als erstes Argument die zweite und als zweites Argument die erste temporäre Datei mitgeben, haben wir die Spalten aus BOOK.VOK vertauscht. Nun nur noch die Prozentzeichen wieder durch -- ersetzen und das Ergebnis der Umtauschaktion in /tmp/BOOK.VOK.paste speichern. Ist alles glatt gegangen, kann die Originaldatei damit überschrieben werden.

Perlen und Ausdrücke

Es geht natürlich auch weniger umständlich – doch dann gelangen wir in den Einflussbereich eigenständiger Skriptsprachen wie z. B. Perl. perl lässt sich mit der Option -p ganz gut als mächtigerer sed-Ersatz benutzen. Wie bei sed leitet die Option -e (execute“) ein auf der Kommandozeile auszuführendes perl-Kommando ein.

[trish@lillegroenn eng_deu]$ perl -pe 's/(^.*)( – )(.*$)/$3$2$1/' BOOK.VOK > /tmp/BOOK.VOK.perl 

Ersetzt werden soll alles (.*) vom Anfang (^) einer Zeile bis zum Ende ($) durch eine umgeordnete Version. Damit der Zeileninhalt nicht verloren geht, speichern wir ihn in runden Klammern zwischen: den Anfang der Zeile vor dem Trennstring -- im ersten Puffer, -- im zweiten und den Rest bis zum Zeilenende im dritten Puffer. Ersetzt wird das Ganze jetzt durch den Inhalt des dritten Puffers ($3), gefolgt vom Trennstring aus dem zweiten ($2) und dem ehemaligen Zeilenanfang aus dem ersten Puffer ($1).

Beachten Sie, dass Sie das Perl-Substitute-Kommando in einfache Anführungszeichen (') setzen. Doppelte Anführungszeichen führen dazu, dass die Shell annimmt, mit $3$2$1 seien die Inhalte von Shell-, nicht Perl-Variablen gemeint.

Als wär’s kein Problem

Der meiner Ansicht nach eleganteste Weg jedoch führt über awk. Im Gegensatz zu paste kommt dieses Tool nämlich auch mit Mehrzeichen-Spaltentrennern klar. Allerdings gibt man den Delimiter hier mit der Option -F (Field separator“) an.

[trish@lillegroenn eng_deu]$ awk -F " – " '{print $2 " – " $1}' BOOK.VOK > BOOK.VOK.awk 

Das awk-„Programm“ in einfachen Hochkommata besteht normalerweise aus einem Muster, auf das ein Kommandoblock in geschweiften Klammern angewandt wird. Da wir die gesamte Datei meinen, brauchen wir kein explizites Muster angeben und begnügen uns mit dem Klammerblock.

Darin weisen wir awk an, den Inhalt der zweiten Spalte ($2), dann den Trennstring -- und zum Schluss den Inhalt der ersten Spalte auszugeben.

Such mir mal

Wie (fast) jedes Shellskript beginnt es mit der Angabe, welche Shell wir verwenden. Natürlich die, mit der wir uns am Besten auskennen, und das wird meist die Linux-Standardshell bash sein:

#!/bin/bash -vx

Beim Entwickeln eines Skripts passieren oft Fehler, weshalb wir zunächst einmal die Debug-Optionen -vx einschalten.

Vorausgesetzt, in /usr/dict/eng_deu liegen nur konvertierte Wörterbuchdateien, halten wir dieses Wörterbuchverzeichnis in der Variable WBDIR fest:

WBDIR=/usr/dict/eng_deu

Wie bei jedem Skript, das für mehr als eine Person bestimmt ist, beginnen wir mit einer Aufrufprüfung: Wenn die Benutzerin mehr oder weniger als einen Suchbegriff als Argument eingibt (also ungleich (not equal“) einen), …

if [ $# -ne 1 ]; then

… spucken wir einfach aus, wie unser Skript bedient werden möchte:

echo "Usage: $0 string"

Netterweise merkt sich ein Shellskript in der Variablen #, mit wievielen Argumenten es aufgerufen wurde. In der Variablen 0 (null) steckt das nullte Argument, also der Kommandoname selbst (ggf. mit angegebenem Pfad).

LinuxUser 06/2001 KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS
Deutschland

Hinterlasse einen Kommentar

  E-Mail Benachrichtigung  
Benachrichtige mich zu: