Dass der Computeralltag auch unter Linux immer wieder für Überraschungen gut ist, ist eher eine Binsenweisheit: Immer wieder funktionieren Dinge nicht oder nicht so, wie eigentlich angenommen. Das Answer-Girl im Linux-Magazin zeigt, wie man mit solchen Problemchen elegant fertig wird.
Wer das vorletzte Answer-Girl in Heft 10/99 gelesen hat, hat sich sicherlich gefragt, warum man inkonsistent groß- und kleingeschriebene HTML-Dateien umbenennen soll, wenn man doch einfach auch die Verweise darauf im HTML-Code ändern kann. Und weil man recht oft in einem ganzen Haufen Dateien bestimmte Zeichenketten auswechseln muss, soll dies das Thema der heutigen Folge sein.
Der Anwendungsmöglichkeiten gibt es vielfältige: Da haben wir mühsam alle auf .htm endenden Dateien nach .html umbenannt und müssen diese Änderung natürlich auch im HTML-Text selbst vornehmen. Oder unser Kollege Windows-User mischt mal wieder fröhlich Groß- und Kleinbuchstaben in Dateinamen und Links (obwohl wir vorher gesagt haben, dass auf unserem Server alle Dateinamen klein geschrieben werden). Natürlich gibt es auch außerhalb von Webseiten genügend weitere Aufgabenstellungen.
<A HREF="pinguin.jpg">Pinguin</A>
pinguin.jpg ist der Name der Pinguin-Bilddatei, und das ominöse A HREF lässt sich besser als “Hier wird die Referenz verankert” merken. Ein Webbrowser stellt von diesem Konstrukt lediglich den von <A …> und </A> eingerahmten Text (in diesem Fall also das Wort Pinguin) dar, und das meist hervorgehoben, sodass die Benutzerin ihn mit Maus, Tastatur o.ä. anwählen kann und daraufhin die pinguin.jpg-Datei angezeigt bekommt.
Wonach suchen wir eigentlich?
Ganz eindeutig: Bevor man nach irgend etwas suchen und es ersetzen kann, sollte man sich im Klaren sein, wonach man eigentlich fahndet. Das mag sich trivial anhören, ist es aber nur in dem Fall, in dem man nach einem String sucht, der lediglich aus Buchstaben, Unterstrichen und Ziffern besteht und definitiv immer gleich geschrieben wird, auch, was die Groß- und Kleinschreibung betrifft. Doch das wäre zu langweilig (ein wenig Gehirnjogging wärmt auf in kalten Wintertagen…), und deshalb suchen wir uns gleich etwas Schwierigeres wie die Links in HTML-Dateien.
Um herauszufinden, wonach wir eigentlich suchen, durchforsten wir am besten zwei oder drei HTML-Dateien stichprobenartig. Das macht bei unübersichtlichem HTML-Code zwar weder besonders viel Spaß, noch ist es in irgendeiner Form ausreichend, aber ehe wir jetzt die nächsten fünf Seiten damit verbringen, unsere Texte in statistischen Analysen aufzubereiten, halten wir es mit der Devise, besser sofort etwas zu tun als später. Dass wir damit gegebenenfalls in eine Falle trampeln und nochmal von Vorn anfangen zu müssen, nehmen wir dafür in Kauf – learning by doing eben.
Unsere Kurzanalyse ergibt, dass glücklicherweise alle Links mit einem <A HREF= in beliebiger Groß- und Kleinschreibung anfangen. Außerdem muss der Dateiname vor dem nächsten > zu Ende sein. An einer Beispieldatei (zum Beispiel index.htm) lässt sich mit grep nach dem String <A HREF= suchen:
grep "<A HREF=" index.htm
Doch was ist, wenn irgendwo auch kleingeschriebene a href auf Dateien verweisen? Die Man-Page zu grep hilft weiter: Die Suche nach case (hier: “Schreibweise”) mit dem Pager-Befehl
/case
trägt Früchte: Die Option -i (oder für weniger Tippfaule --ignore-case (“Achte nicht auf Groß- und Kleinbuchstaben”)) lässt grep unabhängig von Groß- und Kleinschreibung suchen. Und vor lauter Euphorie darüber, dass grepreguläre Ausdrücke unterstützt, versuchen wir, mit
grep -i "<A HREF=.*>" index.htm
den gesamten Verweis zu erwischen: Der Punkt . steht für ein beliebiges Zeichen, das Sternchen * hat zur Folge, dass dieses beliebige Zeichen ein, kein oder beliebig viele Male wiederholt werden darf. .* passt also auf jedwede Kombination aus Buchstaben, Ziffern, Whitespace– und Sonderzeichen und damit problemlos auf Dateinamen und umschließende Anführungs- und Leerzeichen – doch dummerweise nur, sofern der gesamte String in einer Zeile steht. Wenn irgendwo zwischen < und > ein Zeilenumbruch steckt, erwischen wir diese Links nicht.
Jetzt können wir natürlich nur nach HREF suchen und behaupten, dass der Dateiname spätestens in den darauf folgenden zwei Zeilen auftreten wird:
grep -i -A 2 "HREF=" index.htm
Das Rauschen, das durch Wörter wie “Sehreflex” erzeugt wird, ist vermutlich vernachlässigbar, wenn man die Unübersichtlichkeit in Betracht zieht, die die zwei zusätzlich angezeigten, aber nur in Ausnahmefällen relevanten Zeilen verursachen.
Nochmal von vorn
Kleine Sackgasse, in die wir uns manövriert haben, und so suchen wir zur Lösung der Fragestellung “Wie kann ich die kaputten Links wieder ausbügeln?” nach einem neuen Ansatz.
Dabei fällt uns zudem ein, dass grep -i zwar sehr schön, aber auch recht unnütz ist, weil grep zwar suchen, aber nicht ersetzen kann. Doch das ist alles nicht so schlimm, weil es schließlich auch noch eckige Klammern gibt. Diese dienen in regulären Ausdrücken als Joker für die zwischen ihnen stehenden Zeichen:
grep "[Hh][Rr][Ee][Ff]=" index.htm
sucht uns all die Zeilen raus, die die Zeichenkette HREF= in beliebigen Varianten von Groß- und Kleinschreibung enthalten.
Und wenn wir seufzenderweise schon mal zugeben, dass unser erster Versuch gescheitert ist, zeigt ein intensiverer Blick in diverse HTML-Dateien oder -Dokumentationen, dass ein Neuanfang so oder so angebracht ist: Denn bislang haben wir völlig übersehen, dass es neben dem HREF-Attribut auch noch einige andere gibt, denen Dateien zugewiesen werden, zum Beispiel das BACKGROUND-Attribut von BODY oder das SRC-Attribut von Inline-Grafiken (IMG).
Also einmal tief Luft holen und noch einmal nachdenken… Warum nicht gleich ein generelles Muster für Dateinamen finden und nach dem suchen? Schließlich darf innerhalb des Dateinamens oder der Pfadangabe kein Zeilenumbruch stattfinden. Wenn man davon absieht, dass Dateinamen auch im Fließtext auftreten koennen, klingt das nach einer guten Idee. Nur, wie filtert man Dateinamen und Pfade heraus?
In HTML-Dateien ist die Wahrscheinlichkeit, dass verlinkte Dateinamen eine durch Punkt vom Grundnamen abgetrennte, meist drei-, ggf. vierbuchstabige Dateinamenendung haben, sehr hoch, da diese Endung vom Browser herangezogen wird, um das passende Anzeigeprogramm oder den passenden Anzeigemodus zu ermitteln. Die Möglichkeit, dass der Dateiname mit einem Punkt beginnt, ist hier ebenfalls unwahrscheinlich, zumal das unter DOS/Windows nicht erlaubt ist.
Das bisherige Suchmuster lautet also “mindestens ein druckbares Zeichen (mithin Buchstaben, Ziffern und einige Sonderzeichen wie Bindestrich und Minus), ein Punkt, drei Buchstaben, ggf. ein vierter (wie in .html)”. Natürlich könnten auch auf .ps abgekürzte PostScript-Dateien verlinkt werden, aber das vernachlässigen wir in diesem Fall (Hausaufgabe?).
Die Man-Page zu grep verrät unter dem Abschnitt REGULAR EXPRESSIONS, dass der Ausdruck [:alnum:] (“alphanumerisch”) alle Buchstaben und Ziffern erfaßt. Um zudem noch - und _ abzudecken, müssen die mit in die Auswahl aufgenommen werden:
[[:alnum:]_-]
Das mindestens einfache, aber gern mehrfache Auftreten von Zeichen aus dieser Menge fordern wir durch ein nachgestelltes Pluszeichen:
+ The preceding item will be matched one or more times.
Hier zum Testen
Komplexe reguläre Ausdrücke wie diese testen wir am besten erstmal: Dazu kann man selbstverständlich eine Testdatei schreiben – oder aber die sogenannten Here-Dokumente zum interaktiven Testen benutzen. Der etwas wunderlich anmutende Name meint schlicht und einfach Dokumente, die an Ort und Stelle (“hier”) interaktiv erzeugt werden und als Standardeingabe für ein Kommando dienen.
cat << EOF | grep "[[:alnum:]_-]+"
meldet sich mit einem erwartungsfrohen >-Prompt und möchte von uns Eingaben, die cat entgegennimmt und an grep über die Pipe als Eingabe weiterleitet. Unsere Eingabe wird solange an cat weitergeleitet (“<<“), bis wir das vereinbarte Stoppwort (in unserem Fall EOF) eingeben:
> Blablabla > > _- > EOF
Hätten Sie das Ergebnis – nichts – erwartet? Eigentlich nicht, denn die Blablabla– und _--Zeile entsprechen unserem Muster “mindestens ein alphanumerisches, Minus- oder Bindestrichzeichen, gern auch mehrere”. Dass die Zeile mit den Leerzeichen nicht passt, war dagegen zu erwarten.
Was tun? Ein Blick in unser Muster zeigt, dass das Minuszeichen als normales Zeichen, nicht als Zeichen mit Sonderbedeutung gehandhabt wird. Warum sollte das beim Plus anders sein? Es drängt sich der Verdacht auf, dass unser Muster eigentlich “ein alphanumerisches, Minus- oder Bindestrichzeichen, gefolgt von einem Plus” bedeutet. Der Test aufs Exempel:
cat << EOF | grep "[[:alnum:]_-]+" > aa+ > B+ > EOF aa+ B+
bestätigt den Verdacht: Unser Muster paßte auf aa+ und B+, nicht aber auf Blablabla und _-. Was tun? Einfach die normale Bedeutung von + durch das Flucht-(“Escape-“)Zeichen \ auf die in der Man-Page beschriebene Sonderbedeutung “umswitchen”:
cat << EOF | grep "[[:alnum:]_-]\+" > Blablabla > > _- > EOF Blablabla _-
Das Kreuz mit dem \
Genau umgekehrt verhält es sich mit dem Punkt, der Grundnamen und Dateinamenendung voneinander trennt. Da der Punkt in regulären Ausdrücken von vornherein eine Sonderbedeutung (“beliebiges Zeichen”) hat, muss diesmal diese Sonderbedeutung durch das Flucht-(Escape-)Zeichen \ abgeschaltet werden:
[[:alnum:]_-]\+\.
Fehlen noch die Dateinamenendungen. Hier haben jetzt nur noch alphanumerische Zeichen Platz (“.htm“, “.html“, “.jpg“, “.GIF” und “.mp3” beispielsweise). Zum Testen muss erstmal eine ein Zeichen lange Endung reichen:
cat << EOF | grep "[[:alnum:]_-]\+\.[:alnum:]" > hallo.m > Huhu.G > dsf.) > asdad.9 > EOF hallo.m
Dass dsf.) von unserem regulären Ausdruck nicht erwischt wird, ist klar. Aber warum fehlen Huhu.G und asdad.9? [:alnum:] umfasst doch eigentlich auch Großbuchstaben und Ziffern… Allerdings haben die eckigen Klammern die Sonderbedeutung, einen Zeichenpool zu umschließen, aus dem an der jeweiligen Stelle ein Zeichen passen muss. Dieser Zeichenpool umfasst hier :, a, l, n, u, m und überflüssigerweise nochmal ein :, was auch nicht besser gefunden wird, nur, weil es doppelt da steht. Man hätte dafür auch [almnu:] schreiben können. Und hallo.m war der einzige String mit einem Zeichen aus diesem Pool nach dem Punkt.
Also die eckigen Klammern durch das Fluchtzeichen in seiner Bedeutung umswitchen? Das jetzt von unseren Beispielstrings gar keiner mehr gefunden wird, wird klar, wenn man sich mit
cat << EOF | grep "[[:alnum:]_-]\+\.\[:alnum:\]" > hallo.[:alnum:] > hallo.a > EOF hallo.[:alnum:]
ansieht, dass dann auch die eckigen Klammern in ihrer wörtlichen Bedeutung benutzt werden.
Was dann? Angesichts unseres funktionierenden Bereichs "[[:alnum:]_-] liegt die Überlegung nahe, einen Bereich zu bilden, der lediglich eine Auswahlmöglichkeit, nämlich [:alnum:] selbst beinhaltet. Et voilà:
cat << EOF | grep "[[:alnum:]_-]\+\.[[:alnum:]]"
tut genau das, was es soll. Fragt sich nun, wie sich ausdrücken lässt, dass genau drei oder vier [:alnum:]-Zeichen hintereinander stehen müssen. Das Plus hilft da leider nicht weiter, denn es meint “von eins bis unendlich viele des vorhergehenden Zeichens”. Allerdings hält die grep-Man-Page direkt unter der Erklärung zu + auch folgendes bereit:
{n,m} The preceding item is matched at least n times, but
not more than m times.
Sollen – wie in unserem Fall – mindestens drei, maximal aber vier aufeinanderfolgende Zeichen aus dem vorangestellten [:alnum:]-Pool stammen, so sollte uns
grep "[[:alnum:]_-]\+\.[[:alnum:]]{3,4}"
zum Ziel unserer Wünsche führen. Dass es das nicht tut, lässt inzwischen wohl schon jede/n automatisch zum Backslash \ greifen:
grep "[[:alnum:]_-]\+\.[[:alnum:]]\{3,4\}"
Bitte keine Rechnernamen!
Idiotensicher ist die ganze Prozedur jedoch noch nicht: Textstellen wie
1.5MB 03.08.1999
werden ebenfalls von unserem regulären Ausdruck erfasst, obwohl es sich hierbei nicht um Dateinamen handelt. Ebenso werden Rechnernamen aus URLs (www.linux-magazin.de) fälschlicherweise mitgenommen.
Das bekommen wir zumindest in korrekten HTML-Dateien recht gut hin: Darin werden verknüpfte Dateien und URLs in Anführungszeichen gesetzt. Wenn wir ans Ende unseres Suchmusters noch ein – natürlich “escaptes” – " setzen:
[[:alnum:]_-]\+\.[[:alnum:]]\{3,4\}\"
schließen wir zumindest die meisten Zufallstreffer im Fließtext aus. Das Problem mit den Rechnernamen haben wir noch nicht ganz gelöst: Zwar klappt das mit vorbildlichen URLs wie A HREF="http://www.linux-magazin.de/", nicht jedoch, wenn der abschließende Slash fehlt und die Topleveldomain dreibuchstabig ist: A HREF="http://www.linux-mandrake.com". Hier könnten wir noch vorgeben, dass vor dem Suchmuster niemals ein Punkt stehen darf:
[^\.][[:alnum:]_-]\+\.[[:alnum:]]\{3,4\}\"
Das ^ invertiert die Zeichenmenge innerhalb der eckigen Klammer und meint damit “alle Zeichen außer dem (zu schützenden) Punkt”.
Ein Problem bleibt: Wer mit einem Link direkt eine Textmarke in einem Dokument anspringt ("datei.html"), erwischt diesen Dateinamen natürlich nicht. Doch was hindert uns daran, nicht nur das Ausführungszeichen als Dateinamenende zuzulassen, sondern auch das Hashzeichen?
[^\.][[:alnum:]_-]\+\.[[:alnum:]]\{3,4\}[\"#]
Dieser gesamte Ausdruck passt demnach auf alle Zeichenketten innerhalb einer Zeile, die
- mit einem Zeichen beginnen, das kein (
^) Punkt (\.) ist, - auf das mindestens ein Zeichen (
\+) folgt, das ein Buchstabe oder eine Zahl ([:alnum:]), ein Unterstrich (_) oder ein Minus (-) ist. - Daraufhin folgt ein Punkt (
\.), - und danach kommen drei oder vier (
\{3,4\}) alphanumerische ([:alnum:]) Zeichen. - Die Zeichenkette wird abgeschlossen durch ein Anführungszeichen (
\") oder ein Hash (#).
Ersetz mir mal…
Natürlich ließe sich unser Suchmuster noch verfeinern und perfektionieren, doch belassen wir es an dieser Stelle dabei und fangen endlich an, nicht nur zu suchen, sondern auch zu ersetzen. Dazu eignet sich – wie wir schon in Heft 10/99 gesehen haben – die Skriptsprache perl am besten.
perl -pe macht es – ähnlich -e – möglich, eine als Argument angegebene Datei Zeile für Zeile durch einen auf der Kommandozeile angegebenen, aus Perl-Kommandos bestehenden Filter zu schicken (-e steht für “execute”) und das Ergebnis auch noch auf dem Bildschirm ausgedruckt (-p wie “print”) zu bekommen.
Der Filter ist relativ einfach gefunden: Suche unseren regulären Ausdruck und s wie substituiere ihn mit sich selbst, wobei der Dateiname komplett in Kleinbuchstaben gewandelt wird. Netterweise schreibt uns Perl nicht fest vor, welches Sonderzeichen wir zum Abtrennen von Suchmuster und Ersatzstück verwenden sollen: Der zum Beispiel von sed bekannte / ist möglich, das Hashzeichen oder auch das Fragezeichen. Bei der Auswahl eines Trennzeichens sollten wir lediglich aufpassen, dass das Zeichen selbst nicht irgendwo referenziert wird, denn sonst sind Escape-Orgien angesagt, und da vertippt man sich nur allzu leicht… An dieser Stelle vermeiden wir also ganz eindeutig das # und versuchen unser Glück mit ?.
Bevor wir uns jetzt schon mit dem Ersatzmuster herumschlagen, prüfen wir zunächst, ob unser mühsam zusammengestückelter regulärer Ausdruck auch unter Perl besteht: Versuchen wir doch einfach, die verlinkten Dateinamen in der Datei index.html auffällig durch ___ zu ersetzen. Natürlich verändern wir dabei nicht die Datei selbst, sondern lassen die veränderten Daten erstmal durch den Pager less seitenweise auf dem Bildschirm ausgeben. Mit der am Ende angegebenen g-(“global”-)Option sorgen wir dafür, dass nicht nur das erste, sondern alle auf einer Zeile auftretenden Fundstellen ersetzt werden:
perl -pe "s?[^\.][[:alnum:]_-]\+\.[[:alnum:]]\{3,4\}[\"#]?___?g" |less
Gleicher als gleich
Was ist das? Warum findet /___, der Suchbefehl, mit dem in der less-Ausgabe nach ___ gefahndet wird, überhaupt nichts? Nun ja, manche regulären Ausdrücke sind halt gleicher als andere… Ein Blick in die Man-Page zu Perls Auffassung von “Regexps”, (aufzufinden mit man perlre, wie die Man-Page zu perl selbst verrät), erzählt so rein gar nichts über [:alnum:]. Stattdessen werden Ziffern, Buchstaben und der Unterstrich durch \w abgedeckt.
Ein erneuter Versuch mit
perl -pe "s?[^\.][\w-]\+\.[\w]\{3,4\}[\"#]?___?g" |less
ruft immer noch keinerlei Änderungen hervor. Also weiter die Man-Page studieren…
Nach einigen Verzweiflungsausbrüchen ist der Übeltäter ausgemacht: Wir müssen auf ein paar unserer geliebten Escape-Slashes verzichten. Das Plus und die geschweiften Klammern haben bei Perl in erster Linie ihre Sonderbedeutung; “escapen” müsste man sie dann, wenn man sie als Zeichen benutzen will. Unser regulärer Ausdruck in Perl sieht folglich so aus:
[^\.][\w-]+\.[\w]{3,4}[\"#]
Jetzt geht es endlich ans Ersetzen. Wichtig ist, dass am Ende wieder genauso viele Zeichen rauskommen, wie wir reinstecken. Also müssen wir alle Strings, die “durch das Mustersieb fallen”, auffangen. Das geht, indem wir sie in runde Klammern setzen. Zunächst klammern wir das Raster, das tatsächlich den Dateinamen abdeckt:
[^\.]([\w-]+\.[\w]{3,4})[\"#]
Das einleitende Zeichen (ungleich Punkt) und das abschließende " oder # müssen nicht verändert, sondern nur übernommen werden, daher klammern wir sie separat:
([^\.])([\w-]+\.[\w]{3,4})([\"#])
| 1 || 2 || 3 |
In der Reihenfolge ihres Auftreten landen die drei Teile in drei verschiedenen Zwischenspeichern namens 1, 2 und 3. Beim Ersetzen können wir auf sie zugreifen, indem wir ein \ vor die Nummer des Zwischenspeichers schreiben. Ein
perl -pe "s?([^\.])([\w-]+\.[\w]{3,4})([\"#])?\1\2\3?g"
ersetzt also das Suchmuster wieder durch sich selbst, ohne ein Loch zu hinterlassen. Um den Inhalt des Zwischenspeichers Nummer 2, also den Dateinamen, komplett in Kleinbuchstaben umzuschreiben, sind wir dann doch recht dankbar, dass Perls reguläre Ausdrücke ein wenig anders aussehen: Alles, was zwischen einem \L (“lower” – “verkleinern”) und einem \E (“Ende”) zu stehen kommt, wird gnadenlos in kleine Buchstaben umgewandelt. Et voilà, damit hätten wir unseren Filter fertig:
perl -pe "s?([^\.])([\w-]+\.[\w]{3,4})([\"#])?\1\L\2\E\3?g" index.html
Nach eins kommt viele
Bislang haben wir unser Skript auf eine einzelne Datei losgelassen. Jetzt kommt es darauf an, eine Liste sämtlicher HTML-Dateien zu erstellen, die im fraglichen Dateibaum auftauchen.
Dazu sucht man am besten nach allen HTML-Dateien im entsprechenden Überverzeichnis (zum Beispiel /html):
find ~/html -iname "*.HTM" -o -iname "*.html"
Mit diesem Befehl suchen wir im Verzeichnis ~/html nach Dateien, deren Namen auf .HTModer (“-o“) .html enden, wobei Groß- und Kleinschreibung dank der “case-insensitiven” Suche mit -iname egal sind. Achtung, Kontextswitch: Wir sind hier wieder zurück bei den Shell-Wildcards, die durchaus entschieden andere Bedeutungen haben als reguläre Ausdrücke.
Jede gefundene Datei speichern wir temporär in der Variablen i und jagen sie mit ihrer Hilfe durch unseren unter Schweiß und Tränen erstellten Filter.
Aber halt! Dass der nicht perfekt ist (zum Beispiel indem er von perfekt in Anführungszeichen gesetzten Dateinamen ausgeht oder auch Dateinamen in URLs auf anderen Servern ersetzt, auf deren Schreibweise wir möglicherweise keinen Einfluss haben), haben wir schon zugegeben. Daher sollten wir ihn auch nicht völlig ohne Seil und doppelten Boden auf unsere Dateien loslassen.
Wir könnten in unser Skript eine Zeile einbauen, die die ursprüngliche Datei erstmal kopiert, bevor daran irgendwas geändert wird. Doch mit ein bisschen Neugier – ja, und ein wenig Stöbern in Man-Pages, genauer gesagt in der zu perlrun – finden wir auch heraus, dass Perl nett zu uns ist und schon eine Option vorsieht, die automatisch ein Backup anlegt und erst dann all die gewünschten Veränderungen an der Originaldatei vornimmt: -i, ohne Leerzeichen gefolgt von der Dateinamenendung, die wir dem Backup-File verpassen wollen. -i.orig sorgt dafür, dass die unveränderte Datei am Ende der Prozedur unter ihrem alten Namen und der zusätzlichen Endung .orig abgelegt ist. Aus index.html wird index.html.orig, während index.html am Schluss die neue Fassung mit den verkleinerten Dateinamen enthält.
for i in `find ~/html -iname "*.HTM" -o -iname "*.html"`
> do
> perl -p -i.orig -e "s?([^\.])([\w-]+\.[\w]{3,4})([\"#])?\1\L\2\E\3?g" $i
> done
Kontrolle ist besser
Jetzt jede einzelne Datei mit ihrem Original zu vergleichen, um herauszufinden, ob alle Änderungen wie gewünscht verliefen, kann ganz schön anstrengend werden. Und wer wird das schon per Augenmaß machen? Dummerweise ist diff auch nicht so recht zu gebrauchen, denn das vergleicht nur zeilenweise. Gut getroffen hat es, wer wdiff installiert hat, das vergleicht nämlich wortweise.
Die Option -3 sorgt dafür, dass tatsächlich nur die Unterschiede der zwei Dateien angezeigt werden:
wdiff -3 index.html.orig index.html
Natürlich kann man auch das mit einer for-Schleife automatisieren und sich nachher ganz in Ruhe eine Datei anschauen, in der all die Unterschiede zwischen Original und veränderter Datei aufgeführt sind. Doch dann wird dieser Artikel wieder viel zu lang…
Glossar
-
Link
-
Ähnlich den altbekannten “siehe”-Vermerken in Büchern handelt es sich auch bei den Hyperlinks von Webseiten um schlichte Verweise, mit dem Unterschied, dass ein “siehe Pinguin-Abbildung” im HTML-Text etwas komplizierter formuliert wird:
-
reguläre Ausdrücke
-
Viele Unix-Tools, zum Beispiel
sed,awk,grepundperlverwenden Jokerzeichen und Zeichen mit speziellen Bedeutungen, mit denen man Muster, reguläre Ausdrücke (kurz:regexps), zusammenbauen kann, um Aktionen auf bestimmte Daten zu beschränken. -
Whitespace
-
Überbegriff für Zeichen, die bei schwarzer Schrift auf weißem Grund weiß bleiben. Die offensichtlichsten Beispiele dafür sind Leerzeichen und Tabulatoren.
-
Pfade
-
Der Weg zu einer Datei im Dateibaum, d.h. die Auflistung von Verzeichnissen, über die man gehen muss, um zur Datei zu kommen. Beginnt man die Aufzählung beim Wurzelverzeichnis / (zum Beispiel
/usr/local/bin), spricht man vom absoluten Pfad, startet man von einem anderen Directory (meist dem aktuellen Arbeitsverzeichnis, zum Beispiel../../usr/local/bin), vom relativen Pfad. -
Standardeingabe
-
Normalerweise erwartet Ihr Linuxrechner, dass die zu bearbeitenden Daten für ein Programm über die Tastatur kommen. Mit Hilfe der Eingabeumlenkung < kann man diese Standardeingabe auch aus einer Datei holen, mit << aus einem Here-Dokument.
-
Pipe
-
Die “Rohrleitung” | verknüpft die Standardausgabe eines Programms mit der Standardeingabe eines anderen. So kann die Ausgabe des ersten Programms “on the fly” von Programm (“Filter”) 2 bearbeitet werden.
-
Topleveldomain
-
Die zwei bis drei Buchstaben, die hinter dem letzten Punkt in einer textuellen IP-Adresse stehen. Die Topleveldomain kann ein Länderkürzel (de für Deutschland, nl für die Niederlande etc.) oder (vor allem in den USA) eine grobe Beschreibung des Tätigkeitsbereichs der Firma, Organisation oder Privatperson sein, die diese Domain betreibt: com steht für Firmen (“commercial”), gov für Regierungsorganisationen (“government”) oder edu für Bildungseinrichtungen (“educational”).
-
#marke
-
Ein <A NAME=”marke”>Text</A> setzt in einer HTML-Datei ein Sprungziel. Verweist man an einer anderen Stelle oder in einer anderen Datei mit <A HREF=”#marke”>Verweis</A> bzw. <A HREF=”datei.html#marke”>Verweis</A> auf dieses Ziel, bringt einen der Webbrowser automatisch zur Text-Stelle (in datei.html), wenn man diesem Link folgt.
-
sed
-
Der “Streamline-Editor” nimmt alle Daten, die er von der Standardeingabe bekommt, und bearbeitet sie filterartig entsprechend den (auf der Kommandozeile oder in einem sed-Skript) angegebenen “Regeln” (alias sed-Kommandos). Er arbeitet also nicht interaktiv, wie man es von anderen Editoren gewöhnt ist, ist dafür aber hervorragend zur automatischen Textverarbeitung geeignet.
-
~
-
Die Tilde ist eine Abkürzung für das Homeverzeichnis.
-
Wildcards
-
Jokerzeichen, die ursprünglich für die Kommandozeile gedacht waren, aber auch von vielen anderen Programmen benutzt werden. Die bekanntesten sind das Sternchen *, das für null bis beliebig viele, durchaus auch unterschiedliche Zeichen steht, das Fragezeichen ?, das Platzhalter für genau ein Zeichen spielt und eine Auflistung von Zeichen in eckigen Klammern (zum Beispiel [A-Z]), das auf genau ein Zeichen aus der angegebenen Zeichenmenge (im Beispiel: einen Großbuchstaben) passt. Leider haben diese als Joker benutzten Zeichen in regulären Ausdrücken meist eine (manchmal nur etwas) andere Bedeutung, sodass man beides nicht vermengen sollte.
-
$i
-
Auf den Inhalt einer Variablen (hier: i) kann man in der Shell zugreifen, indem man ein $ davor setzt. Im Beispiel wird $i Schritt für Schritt durch jede gefundene Datei ersetzt und perl “zum Fraß vorgeworfen”.




