Home / LinuxUser / 2001 / 06 / The Answer Girl

Newsletter abonnieren

Lies uns auf...

Folge LinuxCommunity auf Twitter

Top-Beiträge

Mandriva gibt Distribution in die Hände der Community
(268 Punkte bei 24 Stimmen)
Neues vom Systemd
(161 Punkte bei 4 Stimmen)
Mandriva in Nöten
(161 Punkte bei 4 Stimmen)

Heftarchiv

LinuxUser Heftarchiv

EasyLinux Heftarchiv

Ubuntu User Heftarchiv

Ubuntu User Heftarchiv

Partner-Links:

Shopping
Topsuche
 
Yatego Deutschlands größte Shoppingmall. 10000 Shops,
3.5 Mio Artikel. Alle Bestseller, Servertechnik und Technik Themenwelten.

Notebooks und Netzwerkhardware bei Mercateo günstig kaufen.
Internet Telefonie mit VoIP Telefonen von Gigaset
Das B2B Portal www.Linx.de informiert über Produkte und Dienstleistungen.
Günstige Digitalkameras finden Sie im Preisvergleich.

Bitte übersetzen Sie!

The Answer Girl

Grep und paste

Als hätten wir uns nicht schon genug gemüht, stellt uns technik.vok vor eine ungleich schwierigere Aufgabe: Hier steht Original und Übersetzung jeweils in einer eigenen Zeile, von den restlichen Vokabeln ist das Paar durch jeweils eine Leerzeile abgetrennt:

 Ab-; Abfall
 waste
 abfuehren
 discharge[…]

Mit sed auf einer Kommandozeile wird das nichts mehr, denn hier müssen wir Zeilenumbrüche durch -- ersetzen und zusätzlich noch Leerzeilen eliminieren. Auch mit perl wird es schwierig, einen noch halbwegs verständlichen Einzeiler dafür zu bauen. Doch zum Glück ist die Datei so regelmäßig aufgebaut, dass – wenn wir einmal die Leerzeilen entfernt haben – immer eine ungerade und die darauf folgende gerade Zeile zusammengehören.

Die Leerzeilen bekommen wir weg, indem wir mit grep all jene Zeilen heraussuchen, in denen mindestens ein Buchstabe a-z und/oder A-Z vorkommt:

[trish@lillegroenn eng_deu]$  grep [a-zA-Z] technik.vok

Jetzt wird es etwas schwieriger. Doch da erinnern wir uns an das cut-Kommando, mit dem sich Spalten aus Textdateien extrahieren lassen. Wenn es cut gibt, muss es doch auch ein paste geben, dass mehrere Spalten zu einer Datei zusammenfügt. Tatsächlich werden wir mit man paste fündig.

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).

Im anderen Fall …

else

… suchen wir in den Vokabellisten im Verzeichnis $WBDIR nach dem ersten Kommandozeilenargument ($1):

        grep -hw "$1" $WBDIR/*

Mit der "Wort-Option" -w sorgen wir dafür, dass grep nur dann etwas ausgibt, wenn das Suchwort als solches (und nicht etwa als Bestandteil eines anderen Worts) in den Vokabellisten auftaucht.

Um Tippfehler bei der Groß- und Kleinschreibung auszuschließen, können wir grep auch noch dazu zwingen, Unterschiede in Groß- und Kleinbuchbuchstaben zu ignorieren:

        grep -hwi "$1" $WBDIR/*

… womit wir eigentlich schon fertig wären und die if-Konstruktion schließen können:

fi

Ausführbarkeitsrechte an unser wb-Skript vergeben …

[trish@lillegroenn /tmp]$ chmod ugo+x wb

… und testen:

[trish@lillegroenn /tmp]$ ./wb 
 #!/bin/bash -vx
 WBDIR=/home/trish/dict
 + WBDIR=/home/trish/dict
 if [ $# -ne 1 ]; then
         echo "Usage: $0 string"
 else
         grep -hwi "$1" $WBDIR/*
 fi
 + [ 0 -ne 1 ]
 + echo Usage: ./wb string"
 Usage: ./wb string

Dank der Geschwätzigkeitsoption -v ("verbose") zeigt die Bash jede einzelne Zeile an, die sie auszuführen gedenkt. Die Zeilen mit dem einleitenden Plus haben wir hingegen der Ausführlichkeitsoption -x ("extensive") zu verdanken, die jedes Mal auch angibt, was die Shell intern wirklich "sieht", wenn sie alle Ersetzungen vorgenommen (z. B. die Inhalte von Variablen ausgelesen) hat. Zum guten Schluss – und leider nicht besonders gekennzeichnet – finden wir in dem Wust natürlich auch noch die Ausgabe, die wir ohne Debug-Optionen zu Gesicht bekommen hätten, hier: Usage: ./wb string.

Auch die Variante mit einem Suchwort funktioniert:

[trish@lillegroenn /tmp]$ ./wb yesterday
 […]
 yesterday – gestern
 only yesterday – erst gestern
 yesterday – gestern
 gestern – yesterday
 vorgestern – the day before yesterday
 […]
Einem Freund empfehlen    Druckansicht Bookmark and Share
Kommentare

Hits
Wertung: 69 Punkte (1 Stimme)

Schlecht Gut

Infos zur Publikation

Infos zur Publikation

LinuxUser 06/2012

Aktuelle Ausgabe kaufen:

Heft bestellen Heft als PDF kaufen

LinuxUser erscheint monatlich und kostet in der Nomedia-Ausgabe EUR 5,50 und mit DVD EUR 8,50. Weitere Informationen zum Heft finden Sie auf der LinuxUser-Homepage.

Im LinuxUser-Probeabo erhalten Sie drei Ausgaben für 3 Euro. Das Jahresabo (ab EUR 56,10) können Sie im LNM-Shop bestellen.

Tipp der Woche

Adobe AIR
Adobe-AIR-Programme installieren und (manuell) starten
Tim Schürmann, 14.05.2012 13:09, 0 Kommentare

Es gibt sie noch: neue Anwendungen, die Adobes Integrated Runtime voraussetzen. Aktuellstes und vermutlich auch größtes Beispiel ist das Adventure Botanicula

Aktuelle Fragen

gibt es ein Kommandozeilen Tool, um ein X11-Fenster in ein Anderes einzubetten?
GoaSkin , 21.05.2012 16:44, 0 Antworten
Das XEmbed-Protokoll ist u.A. dazu gedacht, dass man eine X11-Anwendung in eine andere wie ein Wi...
Apache2, Options -Indexes geht nicht
no no, 12.05.2012 19:01, 8 Antworten
Habe in apache2.conf folgendes stehen: Options -Indexes ...
LInux auf Dell LS H500
Andreas Endresl, 09.05.2012 08:54, 2 Antworten
Habe einen alten Dell Latitude LS H500 nur mit ext. Floppy und CD es geht nur immer eines von den...
Datenwiederherstellung unter Ubuntu 12.04 mit "Simple Backup" nach Umzug von Linux Mint
Christian Lottmann, 07.05.2012 13:33, 0 Antworten
Vor dem Umzug auf Ubuntu 12.04 habe ich unter Linux MInt mit "Simple Backup" voll (15.4.2012) und...
DKMS für den propritären NVIDIA-Treiber
Commander Data, 26.04.2012 22:02, 2 Antworten
Hallo an die Gemeinde. Ich habe hier ein interessantes Stück openSuSE gefunden. http://forums.op...