freeX: Einführung in Perl, Teil 1
|
Perl hier, Perl da, Perl ist immer da!
| |
Perl gehört zu Unix wie die Milch zu den Flakes. Es ist die am
weitesten verbreitete Skript-Sprache auf Unix-artigen Systemen wie
z.B. GNU/Linux oder *BSD. Die Mächtigkeit dieser Systeme wird oft durch
die Mächtigkeit von Perl erheblich erweitert.
|
|
1. Skript vs. compiliertem Programm |
Skript vs. compiliertem Programm
Auf Unix-artigen Systemen werden viele Probleme mit Skripten gelöst. Wer von DOS kommt, wird die Hände über dem Kopf zusammenschlagen, denn dort stand als Skript-artige Sprache meistens nur Batch-Programmierung zur Auswahl - und die ist weder komfortabel noch akzeptabel schnell.
Skriptsprachen unter Unix sind jedoch erheblich effizienter programmiert, so daß ihre Programme ausreichend schnell ausgeführt wird. Skript bedeutet, daß der Quellcode von einem Interpreter direkt ausgeführt wird und nicht vor dem Aufruf erst von einem Compiler in Maschinencode übersetzt werden muß. Ausführbarer Maschinencode wird natürlich schneller ausgeführt als interpretierter Code.
Perl geht hier im Gegensatz zu anderen Skriptsprachen einen eigenen Weg. Oberflächlich gesehen handelt es sich zwar um einen Interpreter, beim genaueren Hinsehen entdeckt man jedoch, daß der Quellcode zuerst compiliert und dann erst ausgeführt wird. Syntaktische Fehler werden daher vor der Ausführung moniert und die Ausführung solcher Programme geschieht schneller als bei echten Interpretern.
Der große Vorteil von Skripten besteht darin, daß sie direkt mit einem Editor geändert und angepaßt werden können. Es muß kein Compiler bemüht werden, sondern das Programm ist direkt ausführbar. Durch sinnvolle Verbindung verschiedener Skript-Sprachen lassen sich viele Probleme zudem sehr einfach lösen. Für die beiden großen Sprachen, Perl und Python, gibt es zudem Bibliotheken, so daß viele Probleme bereits gelöst sind und lediglich miteinander verbunden werden müssen.
Wer Unix-Systeme administriert, wird zwangsläufig auch mit Skripten in Berührung kommen. Viele Routinen, die beim Hochfahren des Systems abgearbeitet werden, sind Skripte, teilweise auch Perl-Skripte. Viele administrative Aufgaben werden von Perl-Skripten durchgeführt.
Für die Manipulation von Texten werden spezielle Werkzeuge wie »grep«, »cut«, »cat«, »tac« und »sed« verwendet. Oftmals werden sie in im Pipelining zusammengeschaltet, um das gewünschte Resultat zu erhalten, wie z.B. der Name eines Benutzers:
grep "^joey:" /etc/passwd|cut -d: -f5|cut -d, -f1
Solche Befehle schütteln erfahrene Administratoren jederzeit aus dem Ärmel, wenn Bedarf besteht. Je nach Wissensstand und Problem fallen sie teilweise auch mehrzeilig aus.
Perl umfaßt vom Umfang her die Funktionalität verschiedener unter Unix üblicher Werkzeuge wie »grep«, »cut«, »cat«, »tac«, »sed«, »awk« und »tr«. Dadurch lassen sich Shellskripte, die auf diese Programme zurückgreifen, in ihrer Ausführung beschleunigen, wenn sie in Perl implementiert werden.
Ein weiterer großer Vorteil von Perl ist die Verfügbarkeit von
speziellen Modulen für viele Anwendungsgebiete. Eine der wichtigsten
Erungenschaften ist z.B. die Datenbankschnittstelle DBI. Durch sie
wird ein Perl-Programm fast mit jeder Datenbank verbunden. Treiber
für die meisten Datenbanken sind vorhanden, so daß man leicht die
zugrundeliegende Datenbank austauschen kann, ohne daß das Programm
großartig geändert werden muß.
Einsatzgebiet: Das Web
Für den Einsatz im World Wide Web hat sich Perl zur prädestinierten
Sprache entwickelt. Aufgrund der hervorragenden Unterstütuzung für
die CGI-Schnittstelle sowie der einfachen Möglichkeit der Anbindung an
Datenbanken und die zusätzliche Einbindung vieler Module lassen sich
damit die meisten Aufgaben relativ einfach bewältigen.
Die Syntax
In Perl geschriebener Quellcode sieht stellenweise ähnlich aus wie C. Wer in C programmiert, wird daher wenig Schwierigkeiten haben, für einige Projekte Perl zu verwenden. Die Verarbeitung von Listen und Zeichenketten sowie die Konvertierung der einzelnen Datentypen in einander ist erheblich einfacher - und fehlertoleranter.
Gundsätzlich gilt zu beachten, daß zwischen Groß- und Kleinbuchstaben unterschieden wird, Befehle mit einem Semikolon abgeschlossen werden müssen und Blöcke wie in C in geschweifte Klammern gesetzt werden. Im Gegensatz zu C muß bei einer Verzweigung oder Schleife jedoch ein neuer abgesetzter Block begonnen werden. Leerzeichen gehören nicht zur Sprache, dürfen jedoch für Einrückungen und zur Lesbarkeit benutzt werden, ebenso Zeilenumbrüche.
Perl versteht vier Typen von Variablen. Normale skalare Variablen umfassen Zeichenketten, Ganz- und Fließkommazahlen. Sie werden durch ein vorangestelltes Dollarzeichen gekennzeichnet und können fast beliebig ausgetauscht werden. Perl übernimmt dann die Konvertierung automatisch. Zeichenketten unterstehen keiner Längenbegrenzung, so daß der Programmierer an der Stelle keine Zeit verschwenden muß.
Der zweite Typ betrifft Arrays oder Listen. Auch sie dürfen beliebig groß werden. Perl vergrößert die Datenstruktur automatisch, wenn es erforderlich ist. Mit speziellen Funktionen lassen sich Elemente und Listen von Elementen an beliebigen Positionen einfügen oder einfach anhängen.
Arrays werden durch ein vorangestelltes At-Zeichen gekennzeichnet. So bezeichnet »@INC« z.B. die Liste der Pfade, in denen Perl nach benötigten Komponenten sucht. Referenziert werden die einzelnen Elemente wie in C mit eckigen Klammern, gezählt wird von 0 an. Daher bezeichnet »$INC[0]« das erste Element aus dem Array.
Als spezieller Modifizierer ist »$#« zu sehen, durch ihn bekommt man die Länge eines Arrays heraus, bzw. es beschreibt den größt-möglichen Index (also die Länge minus 1). Bei einem ein-elementigen Array würde es daher 0 zurückliefern, bei einem leeren Array -1.
Der dritte Typ von Variablen bezeichnet sogenannte assoziative Arrays (bzw. "associative arrays"). Dabei handelt es sich im Prinzip um Arrays, jedoch werden die Elemente nicht durch ihre Position im Array referenziert, sondern durch einen Text. So lassen sich Tabellen oder Zuordnungen realisieren. Assoziative Arrays werden mit einem vorangestellten Prozentzeichen gekennzeichnet.
Wenn Elemente referenziert werden, werden geschweifte Klammern für den Index verwendet. Auch hier wird dem Namen der Variablen ein Dollarzeichen vorangestellt, wenn nicht das gesamte Array gemeint ist. So bezeichnet »%ENV« alle vorhandenen Umgebungsvariablen und »$ENV{'HOME'}« das jeweilige Home-Verzeichnis.
File-Deskriptoren sind der vierte Typ von Variablen. Von ihnen kann entweder gelesen oder geschrieben werden. Genauso wie in C auch, besteht die Möglichkeit, über eine sogenannte "Pipe" die Ausgabe von externen Programmen zu lesen oder eigene Ausgaben als Eingabe für externe Programme zu verwenden.
Falls nicht anders angegeben, gelten Variablen als globale Variablen. Daher ist unbedingt auf unterschiedliche Nomenklatur oder Definition lokaler Variablen zu achten. Letzteres geschieht mit dem Schlüsselwort »my«.
if ($ENV{'PATH_INFO'} eq "edit") {
edit ();
} elsif ($ENV{'PATH_INFO'} eq "insert") {
$foo = "Neu: ". $foo;
insert ();
} elsif ($ENV{'PATH_INFO'} eq "update") {
my $i=1;
while ($i < 10) {
update ($i);
$i++;
}
} elsif ($ENV{'PATH_INFO'} eq "delete") {
remove ();
} else {
banner ();
}
| |
| Verschiedene Sprachkonstrukte in Perl | |
An folgendem Beispiel läßt sich ein Teil der Sprache verdeutlichen.
Verzweigungen und Schleifen
Die einfache Verzweigung »if-then-else« wird in Perl durch das Schlüsselwort »elsif« ergänzt. Dadurch besteht die Möglichkeit, weitere Bedingungen zu testen, wenn die vorherige fehlgeschlagen hat. Mit diesem Konstrukt wird die traditionelle »case«- oder »switch«-Verzweigung überflüssig - dieses Konstrukt ist mächtiger.
Die häufigsten Schleifen, die in Perl-Programmen benutzt werden, sind »while«- und »foreach«-Konstrukte. Während die Semantik des »while«-Konstrukts analog zu anderen Sprachen ist, handelt es sich bei »foreach« um eine Perl-Spezialität.
Dabei durchläuft eine Laufvariable sukzessive alle Elemente der gegebenen Liste. So werden Aktionen für jedes Element eines Arrays durchgeführt. Das folgende Fragment zeigt alle Elemente des Arrays »@foo« auf der Console an.
foreach $i (@foo) {
print "$i\n";
}
Integer-Operationen
Die üblichen Operationen auf Integer- und Fließkommazahlen sind im Sprachumfang von Perl enthalten. Die Umwandlung vom einen in den anderen Typen findet normalerweise "automatisch" statt, abhängig davon, was offensichtlich benötigt wird.
Hinzu kommen Konstrukte wie »$i++«. Damit wird die Variable »$i« um 1 erhöht. Genauso unterstützt Perl »$i--«, wodurch die Variable »$i« um 1 veringert wird.
Darüberhinaus versteht Perl Anweisungen wie »$i += 2«, also zum aktuellen Wert 2 hinzuaddieren und das Ergebnis wieder in der Variablen speichern. Analog dazu werden »-=«, »*=« und »/=« unterstützt.
Abbildung 1: Ausgabe des Beispielprogramms
String-Operationen
Zeichenketten dürfen in einem Perl-Programm beliebig lang werden. Hier kümmert sich der Compiler selbst um den benötigten Speicherplatz und paßt ihn bei Bedarf entsprechend an. Damit wird eine Klasse von Programmierfehlern gleich von vorn herein ausgeschlossen, da sich der Programmierer überhaupt nicht mehr um die Größe von Zeichenketten kümmern muß. Gleiches gilt übrigens für Listen bzw. Arrays.
if ($foo eq "bar") {
}
Der Vergleich zweier Zeichenketten auf Gleichheit wird mit dem speziellen Operator »eq« (von: »equal«) durchgeführt. Unterscheiden sich die beiden Zeichenketten nicht, dann ist die Bedingung wahr und der nachfolgende Code wird ausgeführt.
Soll auf Ungleichheit zweier Zeichenketten geprüft werden, so muß die gesamte Bedingung negiert werden. Das geschieht mit dem »!«-Operator. Die Bedingung sieht dann wie folgt aus:
!($foo eq "bar")
Werden die Klammern und das Ausrufezeichen anders gesetzt, ändert sich damit die Bedeutung erheblich. Die Verzweigung sieht dann wie folgt aus:
if (!($foo eq "bar")) {
}
In diesem speziellen Fall kann man allerdings auch gleich den Perl-Operator für den Test auf Ungleichheit von Zeichenketten »ne« verwenden. Damit sieht die Verzweigung wie folgt aus:
if ($foo ne "bar") {
}
So sind Vergleiche von Zeichenketten intuitiver zu verstehen als in C, was ein Motto von Perl zu sein scheint. Da Zeichenketten keiner Längenbeschränkung unterliegen wie in anderen Sprachen, ist das Aneinanderfügen von Strings erheblich einfacher. Dieses geschieht mit dem Punkt-Operator:
$foo = "Hallo " . "Joey";
Zusätzlich wird das Anhängen von Text auf bequeme Weise unterstützt. Der Operator ».=« funktioniert wie von Zahlen erwartet. Die folgenden Befehle haben daher das gleiche Ergebnis wie das letzte Beispiel:
$foo = "Hallo "; $foo .= "Joey";
Unterfunktionen
Um Programme übersichtlicher zu gestalten und mehrfach benutzte Programmteile nur einmal zu schreiben werden sie normalerweise in Subroutinen oder funktionen ausgelagert. Perl ist hier keine Ausnahme und unterstützt das Konzept modularer Programmierung. Innerhalb des Programms werden Subroutinen durch das Schlüsselwort »sub« gefolgt vom Namen eingeleitet.
In einer Unterfunktion sollten alle Variablen lokal deklariert werden, da sie sonst als global angenommen werden. Wenn irgendwo im restlichen Programm eine Variable mit dem gleichen verwendet wird, würden sie sich gegenseitig überschreiben. Das führt mitunter zu sehr merkwürdigen Effekten.
Werden Parameter an Unterfunktionen übergeben, so speichert Perl sie
für die Subroutine in der Variablen »@_«, so daß aus der Routine mit
»$_[0]« das erste Element gelesen werden kann. Alternativ wird
»shift« benutzt, wodurch das erste Element aus der Argumentliste
gelesen und anschließend gelöscht wird.
Real Code
Mit dem bisher gelernten lassen sich einfache Aufgaben bereits lösen. Die Ausgabe des folgenden Beispiels sehen Sie in der nebenstehenden Abbildung.
sub tentimes
{
my $text = shift;
my $i = 0;
while ($i < 10) {
printf "%s\n", $text;
$i++;
}
return 1;
}
tentimes ("So geht es.");
if (tentimes ("So aber auch.")) {
print "Erfolgreich.\n";
}
| |
| Eine kleine Unterfunktion | |
Das Hauptprogramm besteht aus dem Code, der keine Subroutine ist. Unterfunktionen dürfen vor oder nach dem Hauptprogramm definiert werden.
Dieses Programm schreibt lediglich Text auf den Bildschirm. Der Text wird dabei aus den Argumenten der Routine gelesen. Eine lokale Laufvariable fungiert als Zähler für die Ausgabe-Schleife. Der letzte Befehl der Routine »return 1« beschreibt den Rückgabewert, der vom aufrufenden Programmteil abgefragt werden kann. Das wird mit dem zweiten Aufruf von »tentimes« demonstriert.
In der nächsten Ausgabe werden weitere Möglichkeiten sowie externe Module beschrieben.