Der Name des aktuellen Programms |
Unter den vielen spezialisierten und vordefinierten Variablen gibt es die Variable $0, die den kompletten Pfad des ausgeführten Scripts enthält:
|
Programmparameter |
Da Perl direkt von C "abstammt", ist auch die Umstellung, was Programmargumente angeht, nicht groß. Die Stehen in @ARGV, einem ansonsten ganz normalen (also auch manipulierbaren) Array:
Umgebungsvariablen |
Eine vordefinierte HashTabelle %ENV enthält die Namen der Umgebungsvariablen und ihre Werte. Man braucht sie nur auslesen:
|
Welche Umgebungsvariablen sind definiert:
|
Schliesslich eine einfache Ausgabe aller Umgebungsvariablen:
|
Aktuelles Datum und Uhrzeit |
Die Funktion time() liefert die aktuellen Epochensekunden. Die spezielle Variable $^T speichert die Zeit des Programmbeginns, auch in Epochensekunden. Mit Hilfe von localtime() kann man diesen Wert in seine Komponenten zerlegen.
|
Grundlegende Datumsberechnungen lassen sich auf Basis der Epochensekunden erledigen, indem man mit Hilfe von Time::Local (Standardmodul) ein Datum in Epochensekunden umwandelt und mit diesen einfach rechnet.
Abstrakter geht es mit dem Modul Date::Calc. Zu finden auf CPAN - ComprehensivePerlArchiveNetwork.
Zeichenkettenersetzung in Strings |
Auf Grund der mächtigen eingebauten Funktionen macht man das in Perl mit Einzeilern. Nur hier zur Demonstration als Funktion:
|
Da die Parameterübergabe ByReference in Perl möglich, aber nicht üblich ist, wird hier das Ergebnis als Return-Wert übergeben.\Q und \E dienen dazu, den Suchbegriff zu quoten. Ansonsten würde nach dem regulären Ausdruck in $s1 gesucht.
idiomatisches Funktionsargumente-Entnehmen |
Da dieses Dokument PerlIdioms heisst, soll es auch ein wenig um solche gehen. So zum Beispiel das idiomatische Argumenteverarbeiten via shift.
|
Der shift Operator nimmt im Normalfall als Argument ein Array an, von dem er das erste Element entfernt und zurückgibt. Bekommt shift keine Argumente, verwendet es @_. Ein argumentloses shift gibt also immer das nächste Argument der Funktion zurück. Befindet sich ein argumentloses shift ausserhalb einer Funktion im Hauptprogramm, wird es nicht von @_, sondern von @ARGV Elemente entnehmen.
Das wirkt zwar etwas verwirrend, ist aber mit die populärste Methode Funktionsargumente zu verarbeiten. Die zweite populäre Variante (und aus Sicht der Verwender anderer ProgrammierSprachen die "bessere") ist die Verwendung folgender Methode:
|
Der Vorteil für den SoftwareEntwickler liegt auf der Hand: die Ähnlichkeit zu SpracheCee, SpracheJava und und und. Dennoch bietet die shift-Variante eine Möglichkeit, die es so populär macht:
|
Allgmein ist "man" sich einig, dass die Listenvariante stets zu empfehlen ist, wenn viele Argumente übersichtlich zu verarbeiten sind.
Parameterübergabe By Reference |
Real beobachtbarer Perl-Code enthält relativ selten Parameterübergaben "by Reference" (bR). Aber es ist zumindest bei Skalaren leicht möglich. Skalare, die nicht w. o. dem Argumentarray @_ entnommen werden, wirken an sich schon als bR:
|
Arrays und Hashes werden bei der Parameterübergabe automatisch in die Einzelelemente aufgelöst. Will man hier bR, dann muss explizit eine Referenz mit "\" erzeugt werden:
|
Obiger Code (ungetestet) übergibt nur zwei skalare Referenzen an das Unterprogramm und zählt die Array-Elemente.
Die obige Schreibweise mit $h_hash und $a_array (bzw. $p_skalar) ist nur ein persönliche Schreibweise um Referenzen im Zeilenfokus eindeutig lesbar und verwendbar zu machen. -- HelmutLeitner
Die Bedeutung des & |
Das & vor Funktionsaufrufen ist eigentlich ein Relikt aus Perl4. Es gilt in Perl5: In der Regel ist es nicht nur überflüssig, sondern sogar gefährlich. Um eine Funktion aufzurufen, reicht völlig:
|
Um eine Funktion ohne Argumente aufzurufen, empfiehlt sich folgendes:
|
Das entspricht auch dem, was man von SpracheCee bzw. SpracheJava gewohnt ist.
Verzichtet man auf die Klammern, muss die Funktion vorher deklariert sein, weil sonst der Parser nicht erkennt, dass das ein Funktionsaufruf ist:
|
Warum kein & ? |
Das & hat eine besondere Bedeutung, besonders wenn man auf die Parameterklammern verzichtet:
|
Hier passiert nämlich etwas ungewohntes: Die Funktionsargumente in @_ werden _nicht_ lokalisiert, d.h. funktion() erhält die Argumente der übergeorneten Funktion:
|
Verwendet man das & _und_ Klammern, bewirkt man auch ein spezielles Verhalten: man schaltet die Funktionsprototypenprüfung ab. Prototypen sind eine umstrittene Geschichte, sind sie aber für eine Funktion definiert, kann das & dazu führen, falsche Parameterübergaben nicht zu bemerken:
|
Wann doch & ? |
Einmal zum Erschaffen von Referenzen auf benannte Funktionen
|
Und schliesslich eine weiter Ausnahme: goto. SoftwareEntwickler wissen, dass goto so gut wie immer eine schlechte Idee ist. In Perl gibt es eine Ausnahme:
|
Schliesslich _kann_ das & zum Dereferenzieren von Funktionsreferenzen dienen, dabei gelten allerdings die gleichen Warnungen wie bei normalen Funktionsaufrufen.
---
idiomatische Verwendung von local und speziellen Variablen |
Das Schlüsselwort local ist eigentlich eine Geschichte für sich. Es bewirkt eine Lokalisierung einer globalen Variablen, es erschafft keineswegs eine neue Variable, sondern lediglich einen neuen Speicherplatz. Zur Lebenszeit der Funktion, die eine Variable local()isiert hat, hat diese globale Variable einen anderen Wert und wird nach Beendigung der Funktion wieder zurückgesetzt. In Perl6 wird dieses Schlüsselwort zur Vermeidung von Verwirrung zu 'temp' umbenannt.
|
Mit Hilfe von local kann man also globale Variablen für eine Zeit so belegen, wie man will und kann sich sicher sein, dass man ihren Wert nicht auf Dauer zerstört. In Kombination mit Perls vordefinierten superglobalen Variablen ergeben sich viele Konstrukte, die man immer wieder findet.
|
Im obigen Beispiel wird $/ (${INPUT RECORD SEPERATOR}?) lokalisiert und auf undef gesetzt (weil nicht initialisert). Der <> Operator liest nun ein Record aus der Datei und das bis zum EOF, weil $/ ja undef ist. Nachdem die Funktion sich beendet hat, ist $/ wieder auf seinem Ursprungswert, die Umgebung wird nicht behindert.
Zum "Aufsaugen" einer Datei hat sich folgendes Idiom breitgemacht:
|
Man kann das auch ungehindert einsetzen und es ist _wesentlich_ effektiver als folgende, zwar lesbare, aber schrecklich aufwendig Alternative, die den Aufbau einer internen Liste forciert.
|
Um es auf die Spitze zu treiben kann man in begrenzt wichtigen Quelltexten folgendes verwenden und sich sogar das eigenständige open() und close() sparen:
|
Denn hier übernimmt Perl das Öffnen der Datei und auch die Fehlermeldung setzt es korrekt ab. Zurecht sollte soetwas vermieden werden, wenn Fehler beim Öffnen anders als durch direktes warn()en nach STDERR abgefangen werden sollen. Ausserdem riskiert man Unverständnis bei denen, denen die viele Magie dieser Zeile nicht bekannt ist.
Hier fliessen nämlich 3 PerlIdioms ein: local, das habe ich erklärt. Der Ausdruck "<>" ist gleichbedeutend mit "< ARGV >". Das magische Dateihandle *ARGV bewirkt, dass alle Elemente in @ARGV als Dateinamen betrachtet werden. Wird von *ARGV gelesen, wird also die erste Datei geöffnet (im Fehlerfall eine Warnung ausgegeben) und an *ARGV geliefert. Ist diese Datei bis zum Ende gelesen, wird die nächste geöffnet, usw..
Als sei das nicht genug ist natürlich zu beachten, dass die Zuweisung der Liste (@array,$rest) = totalegal _immer_ dazu führt, dass $rest undefiniert ist und alle zugewiesenen Elemente nach @array gehen.
Schwartzsche Transformation |
Ein unglaublich wichtiges PerlIdiom ist die Schwartzsche Transformation. Sie ist auch ein Idiom, das _nur_ positiv zu bewerten ist. Benannt ist die Geschichte nach Randal L. Schwartz, dem Erfinder.
Problem: Ich sortiere eine Liste von "Dingen" nach einem bestimmten Kriterium, und zwar ist dieses Kriterium eine Funktion des "Dings", die einigermassen aufwendig ist. Beispielsweise das Sortieren von Dateinamen nach dem Alter der Datei.
Der erste Ansatz ist:
|
Das funktioniert prima, ist nur unerträglich ineffektiv, da die Feststellung des Alters für eine Datei viele Male durchgeführt wird (perls sort() verwendet QuickSort und neuerdings auch MergeSort).
Lösung: Man berechnet das Alter der Datei nur einmal und sortiert dann. Aus der eindimensionalen Ausgangsliste wird eine 2-Dimensionale, bei der jedes Element nicht nur den Dateinamen, sondern auch das Dateialter enthält. Nach der Sortierung werden die Dateialter wieder weggeworfen, die Liste wird wieder eindimensional.
Umgesetzt wird das ganze _ohne_ temporäre Arrays, sondern nur mit perl-internen Listen und dem PowerTool? map.
|
Gelesen werden muss dieser Code von hinten nach vorne: Das unterste map macht aus jedem Element der Ausgangsliste eine anonyme Arrayreferenz, die das Originalelement und das Dateialter enthält. Der sort-Block sortiert nun anhand des zweiten Elementes jeder Arrayreferenz. Das obere Map extrahiert nun aus jedem Array wieder das erste, das Ausgangselement.
Dieses PerlIdiom sollte man wirklich kennen, weil man unter Garantie darauf stoßen wird, wenn man sich mit Perl beschäftigt.
Arbeit mit Dateien |
Da Perl bekanntermaßen die Sprache zur Textmanipulation ist, ist auch die Arbeit mit Dateien eine zentrale Angelegenheit, die kaum in wenigen Worten zu erklären ist.
Um WiederkehrendeBedürfnisse zu befriedigen, hier kurz das gängige Muster. (Achtung: open() mit 3 Parametern ist erst ab perl 5.6.1 möglich. Aktuell ist 5.8.0, bei dem open() weitere, geniale, Tricks hat)
|
Einen kurzen Abriss enthält `perldoc -f open`. Kennen sollte man natürlich die besonderheiten von close(), sowie seek(), tell() und read(), die alle sehr intuitiv nutzbar sind.
Zur Vermeidung von gleichzeitigen Zugriffen sei flock() erwähnt, Doku auch dazu in perlfunc.
Modularisierung |
Es gilt: TIMTOWTDI. Perl ist mitunter so beliebt, weil es so modular ist. Module sind eigenständige Dateien, die ihren eigenen Namensraum (aka Package) definieren. In diesem Package definieren sie Funktionen bzw. Methoden. Ein Modul kann sowohl eine Klasse als auch eine einfache Bibliothek sein. CGI.pm, das wichtigste Modul zur CgiProgrammierungMitPerl, kann sowohl Funktions- als auch Objektorientiert verwendet werden.
Eine einfache Bibliothek (typischerweise in "Foo.pm"):
|
Verwendung desselben Moduls:
|
Moechte man bestimmte Attribute des Moduls exportieren, ohne immer bei dessen Verwendung den vollstaendigen Modulnamen voranstellen zu muessen:
|
Verwendung des Moduls:
|
Eine Klasse:
|
Und Verwendung:
|
Näheres in `perldoc perlobj` (u.A.). Vgl. OopInPerl.
Benchmarks (KategorieZeit) |
Dafür hat Perl ein parktisches StandardModul?, genannt: Benchmark, wie sonst?
|
Dieses kleine Stückchen Code wird die beiden anonymen Routinen jeweils 1 Million mal ausführen und sehr exakt die Laufzeiten berechnen und danach tabellarisch bewerten.
Frage: Heißt diese Routine wirklich "cmpthese". In meiner Version von Benchmark.pm gibt es nur eine analoge Funktion "timethese"?