Alles nur geklaut

Jetzt wollen wir viele Dateien bearbeiten, am besten alle, die im aktuellen Verzeichnis stehen. Sowas sollte doch auch schon vor uns jemand mal gemacht haben. Perl-Skripte gibt es auf dieser Welt und im WWW viele, das mit der verständlichen Dokumentation ist hingegen so eine Sache. Ein Lichtblick für Neu-Perlianer/innen ist Brigitte Jellineks "Perlwelt" [2], die in kleinen, gut überschaubaren Perl-Skripten praktisch relevante Aufgaben löst.

Hier finden wir unter Viele Webseiten ändern [3] ein Skript, das in allen HTML-Dateien im aktuellen Verzeichnis die Umlaut-Entities in echte ISO-Umlaute umwandelt (Abbildung 1) und mit

$^I = ".bak";

zuvor sogar immer eine Backup-Datei mit der Endung .bak anlegt.

Abbildung 1: Abschreiben von Bjellis Perlwelt

Dieses letzte Feature markieren wir zunächst einmal mit einem # am Zeilenanfang so, dass der Interpreter es nicht beachtet. Indem wir die Zeile auskommentieren, ergibt sich als netter Nebeneffekt, dass wir einstweilen noch gar keine Dateien schreiben, sondern das Ergebnis auf der Standardausgabe angezeigt bekommen. Zum Testen ohnehin viel besser!

In Perl beginnen einfache (skalare) Variablen immer mit einem Dollarzeichen, und eine so komische Variable wie $^I muss schlichtweg etwas Vordefiniertes sein. Tatsächlich erklärt man perlvar, dass damit das Inplace-Editing, also das Editieren der gerade bearbeiteten Datei ein- oder abgeschaltet wird.

Auch die nächste Zeile,

@ARGV = <*.html>;

sieht nach einer vordefinierten Variablen aus, wegen des vorangestellten @ ein Array, also ein ein- oder mehrdimensionales Wertefeld. @ARGV, der "Argumentvektor", ist eindimensional und enthält laut der perlvar-Manpage die Kommandozeilenargumente des Skripts. Wir sind also sehr gewitzt und definieren erst innerhalb des Programms, mit welchen Argumenten es eigentlich aufgerufen wird: natürlich mit allen, die auf .html enden.

Perl sorgt bereits von sich aus dafür, dass die Argumentdateien geöffnet werden und man über das Handle <> Zugang zu den darin enthaltenen Daten bekommt. Wir müssen den Inhalt also lediglich zeilenweise abgreifen, bis es keine Zeilen mehr gibt:

while( $zeile = <> ) { }

Ein klarer Fall für eine Schleife, die immer wieder durchlaufen wird, solange (while) die in runden Klammern stehende Bedingung stimmt. Ob wir die zur Zwischenspeicherung benötigte Variable $zeile wie in [3] vorab mit der my()-Funktion deklarieren oder sie erst da entstehen lassen, wo wir sie brauchen, spielt bei Perl keine Rolle. Erst im Zusammenhang mit objektorientierter Perl-Programmierung wird my() wirklich wichtig. Allerdings schadet es nicht, sich von vornherein daran zu gewöhnen. Wenn wir den Inhalt von $zeile innerhalb der geschweiften Klammern mit

print $zeile;

wieder ausgeben, sollte unser Skript einfach den Inhalt der .html-Dateien im aktuellen Verzeichnis Zeile für Zeile ausgeben. Testen wir das in einem Verzeichnis, das (nicht zuviele) HTML-Files enthält. Da cgks vermutlich nicht im Suchpfad liegt, geben wir den Pfad mit an (z. B. den Punkt als Abkürzung für das aktuelle Verzeichnis).

pjung@chekov:~/answergirl$ ./cgks
 bash: ./cgks: No such file or directory

Keine Datei, kein Verzeichnis dieses Namens? Da ist etwas faul. Wir haben wohl vergessen, uns selbst mit chmod u+x cgks Ausführbarkeitsrechte zuzugestehen.

Muster erkennen

Da uns das Skript brav die Dateiinhalte ausgibt, können wir nun die Links raussuchen. Perl kennt das schöne Konstrukt der "per Default zu bearbeitenden Daten", die sich in der Variablen $_ verstecken. Wenn man nach etwas sucht, braucht man gar nicht angeben, worin zu suchen ist, wenn man den Inhalt von $_ meint. Wir wollen den Inhalt von $zeile bearbeiten und legen ihn daher mit

$_ = $zeile;

im Default ab. Gibt es Links in dieser Zeile? Wenn ja, folgen die auf ein <A HREF= innerhalb von Gänsefüßchen ("). Den Schluss bildet ein >. (Um das Skript nicht unnötig zu verkomplizieren, gehen wir davon aus, dass keine Zeilenumbrüche in dieser Zeichenfolge enthalten sind.) Als regulärer Ausdruck sieht das so aus:

<A HREF=\"(.*)\">

Die Gänsefüßchen müssen wir mit dem Backslash escapen, da sie auch in Perl zum Begrenzen von Stringinhalten benutzt werden. In runden Klammern merken wir uns die Referenz (entweder eine URL oder eine lokale Dateiangabe), eine beliebig lange Folge beliebiger Zeichen, .* abgekürzt.

Leider haben reguläre Ausdrücke die dumme Angewohnheit, immer soviel wie möglich abdecken zu wollen. Wenn nach dem HREF mehrere "> auf der Zeile vorkommen, wird die obige Regexp bis zum letzten Vorkommen alles in den runden Klammern speichern. Diese Gier gewöhnen wir ihr ab, indem wir das in diesem Zusammenhang etwas schwer zu erklärende Ein- oder Keinmal-Zeichen ? hinter .* setzen:

<A HREF=\"(.*?)\">

Um im Inhalt von $_ danach zu suchen, nutzen wir den "match"-Operator m/Muster/, dem wir mit einem i-Flag am Ende gleich sagen, dass a href auch kleingeschrieben werden darf ("case-insensitive Suche"). Auch wollen wir alle auf der Zeile vorkommenden Links einsammeln und bemühen dazu das Flag g ("global"):

@dateien = m/<A HREF=\"(.*?)\">/gi;

Das, was jeweils in den runden Klammern landet, speichern wir in einer Array-Variablen namens @dateien und gehen sie Schritt für Schritt durch:

foreach $datei ( @dateien ){ }

Die jeweils aktuelle Referenz legen wir dazu in der Variablen $datei ab, die als "Laufvariable" der foreach-Schleife automatisch in $_ landet. Um nur dann etwas zu ändern, wenn es sich um eine Referenz auf eine lokale Datei handelt, prüfen wir, dass ihr Inhalt nicht mit einem Protokoll wie ftp oder http beginnt (andere Protokolle wie gopher können wir vernachlässigen):

if ( ! /(ftp|http):\/\//i ){ }

Das m vom Match-Operator darf weggelassen werden, und "ftp:// oder http://" lässt sich zu (ftphttp):// verkürzen. Dabei dient das Pipe-Zeichen als logisches Oder. Da die Schrägstriche bereits das Muster einrahmen, müssen wir sie escapen, und um nicht auf Groß- und Kleinschreibung zu achten, nutzen wir das i-Flag des Match-Operators. Zu guter Letzt sorgt das Ausrufezeichen dafür, dass die Bedingung gerade dann erfüllt ist, wenn das Muster nicht gefunden wird.

LinuxCommunity kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • The Answer Girl
    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.
  • Doppeltes Lottchen
    Batsh schlägt zwei Fliegen mit einer Klappe: In dieser Sprache geschriebene Programme lassen sich sowohl in Bash-Skripte als auch in die unter Windows genutzten Batch-Dateien übersetzen.
  • Bildverarbeitung mit den Skriptsprachen Perl und Python
    Mit nur wenigen Zahlen Code korrigieren Sie das Format digitaler Bilder, passen die Metadaten an oder beschriften die Fotos für den Upload in ein Online-Album.
  • LaTeX mit Daten aus externen Quellen anreichern
    Mit Skriptsprachen wie Perl oder Python verheiraten Sie Datenbanken und LaTeX zu einem Dream-Team beim Seriendruck.
  • Bilder verarbeiten mit der Magick Scripting Language
    Die Magic Srcipting Language hilft Ihnen, Bilder mit einem fest definierten Satz an Parametern zu bearbeiten. In Verbindung mit geschickter Shell-Programmierung nutzen Sie so die Ressourcen eines Systems optimal aus.
Kommentare

Infos zur Publikation

LU 10/2017: Daten retten & sichern

Digitale Ausgabe: Preis € 8,50
(inkl. 19% MwSt.)

LinuxUser erscheint monatlich und kostet 5,95 Euro (mit DVD 8,50 Euro). Weitere Infos zum Heft finden Sie auf der Homepage.

Das Jahresabo kostet ab 86,70 Euro. Details dazu finden Sie im Computec-Shop. Im Probeabo erhalten Sie zudem drei Ausgaben zum reduzierten Preis.

Bei Google Play finden Sie digitale Ausgaben für Tablet & Smartphone.

HINWEIS ZU PAYPAL: Die Zahlung ist ohne eigenes Paypal-Konto ganz einfach per Kreditkarte oder Lastschrift möglich!

Stellenmarkt

Aktuelle Fragen

Lieber Linux oder Windows- Betriebssystem?
Sina Kaul, 13.10.2017 16:17, 2 Antworten
Hallo, bis jetzt hatte ich immer nur mit
IT-Kurse
Alice Trader, 26.09.2017 11:35, 2 Antworten
Hallo liebe Community, ich brauche Hilfe und bin sehr verzweifelt. Ih bin noch sehr neu in eure...
Backup mit KUP unter Suse 42.3
Horst Schwarz, 24.09.2017 13:16, 3 Antworten
Ich möchte auch wieder unter Suse 42.3 mit Kup meine Backup durchführen. Eine Installationsmöglic...
kein foto, etc. upload möglich, wo liegt mein fehler?
kerstin brums, 17.09.2017 22:08, 5 Antworten
moin, zum erstellen einer einfachen wordpress website kann ich keine fotos uploaden. vom rechne...
Arch Linux Netzwerkkonfigurationen
Franziska Schley, 15.09.2017 18:04, 0 Antworten
Moin liebe Linux community, ich habe momentan Probleme mit der Einstellung des Lan/Wlan in Arc...