LPI-Prüfungsvorbereitung LPIC-2

> # Perl auf die Schnelle

> Perl ist eine komplette Programmiersprache, die heute nahezu unendlich viele Möglichkeiten bietet und deren Erlernung sicherlich mehr benötigt, als einen solchen kurzen HTML-basierten Kurs. Trotzdem soll diese Seite einen Schnelleinstieg ermöglichen, der die grundlegenden Konzepte der Sprache darstellt und Lust auf eigene Weiterentwicklung machen soll.

> Perl ist eine Scriptsprache, die zur Ausführung einen Perl-Interpreter benötigt. Der Interpreter selbst arbeitet aber auch als eine Art Compiler, das heißt, der ganze Quelltext wird am Stück gelesen und analysiert, bevor er ausgeführt wird. Das bedeutet in der Praxis zwar eine etwas längere Ladezeit für ein Programm, vermeidet aber Interpreter-typische Laufzeitfehler und ergibt einen schnelleren Programmablauf.

> Eine Perl-Quellcodedatei wird wie ein Shellscript erstellt und mit chmod ausführbar gemacht. Die erste Zeile der Quellcodedatei bestimmt - wie bei Shellscripts auch - den Interpreter. Jede Quellcode-Datei beginnt also mit der Zeile

>       #!/usr/bin/perl

> Das bedingt natürlich, dass der Perl-Interpreter auch in /usr/bin liegt. Ansonsten muß die Zeile entsprechend angepasst werden.

> ## Erste Anfänge

> Um ein "Hallo Welt" Programm in Perl zu schreiben, benötigen wir gerade mal zwei Zeilen:

>       #!/usr/bin/perl
>       print "Hallo Welt\n";

> Wenn wir diese Zeilen in die Datei "hallo.pl" schreiben (die Endung .pl ist keineswegs vorgeschrieben) und diese Datei mit

>       chmod +x hallo.pl

> ausführbar machen, dann haben wir unser erstes Perl-Programm geschrieben.

> Was gibt es zu diesem Beispiel noch zu sagen? Die zweite Zeile enthält die Perl-Anweisung `print`, die als Argument einen String (Zeichenkette) bekommt. Wie in C, so werden auch in Perl die Sonderzeichen mit einem Backslash dargestellt, \n meint den Zeilentrenner. Auch wie in C, muß jede (auch die letzte) Anweisung durch ein Semikolon (;) abgeschlossen werden.

> Unser nächstes Programm wird schon etwas mehr machen, wir lassen den Anwender Daten eingeben. Um eine Dateneingabe zu erreichen, benötigen wir Variablen. Einfache Variablen bekommen in Perl grundsätzlich ein Dollarzeichen vorangestellt, auch bei der Zuweisung. Hier unterscheiden sich Perl und Shells wie die Bash. Perl bietet als Operator bereits die Standard-Eingabe an, die hier einfach <STDIN> heisst. Eine Eingabe wird also folgendermaßen erzeugt:

>       print "Nennen Sie Ihren Namen ";
>       $name = <STDIN>;

> Der Wert von $name enthält an diesem Punkt noch das abschließende Enter-Zeichen (also den Zeilentrenner. Hätte jemand hier "Hans" eingegeben, so enthielte die Variable $name jetzt also "Hans\n". Um diesen Zeilentrenner wieder loszubekommen, benutzen wir den `chop` Operator, der das letzte Zeichen einer skalaren Variable entfernt:

>       chop($name);

> Jetzt können wir den User mit Namen begrüßen, indem wir die Variable einfach in der `print`-Anweisung benutzen:

>       print "Hallo $name, nett Sie zu sehen\n";

> Zusammengesetzt entsteht daraus also das folgende Programm:

>       #!/usr/bin/perl
>       print "Nennen Sie Ihren Namen ";
>       $name = <STDIN>;
>       chop($name);
>       print "Hallo $name, nett Sie zu sehen\n";

> Die bisher benutzte Variable ist ein sogenannter skalarer Variablentyp. Für den Anfang können skalare Variablen mehrere Zeichen enthalten, Buchstaben, Sonderzeichen oder Ziffern.

> ## Kontrollstrukturen

> Kontrollstrukturen einer Programmiersprache sind Mechanismen, mit denen der lineare Ablauf eines Programms verändert werden kann. Beide oben genannten Beispiele haben einen solchen linearen Ablauf. In jedem Fall werden die enthaltenen Zeilen nacheinander abgearbeitet. Nur die einfachsten Programme arbeiten mit solchen linearen Abläufen.

> ### Blockbildung

> Wie schon unter C können mehrere einzelne Anweisungen mit geschweiften Klammern zu einem Block zusammengefasst werden. Vereinfacht gesagt gilt ein Block von Anweisungen wie eine einzelne Anweisung.

> ### Bedingungsüberprüfungen

> Eine Programmiersprache ist immer geeignet, bestimmte Bedingungen zu überprüfen und so zu verschiedenen Abläufen zu kommen. Der Standardweg hierfür ist immer die if-Anweisung. In Perl sieht eine einfache if-Anweisung genauso aus wie in C:

>       if ($zahl1 >= $zahl2) {
>         $zahl3 = $zahl1 - $zahl2;
>       } else {
>         $zahl3 = $zahl2 - $zahl1;
>       }

> Frei übersetzt könnten wir das folgendermaßen formulieren:

>       Wenn $zahl1 größer oder gleich $zahl2
>         dann ist $zahl3 das Ergebnis der Rechenoperation $zahl1 minus $zahl2
>       ansonsten
>         ist $zahl3 das Ergebnis der Rechenoperation $zahl2 minus $zahl1

> Allerdings ist das sozusagen eine Sonderform der if-Anweisung, die klassische Perl-Form ist genau andersherum. Sie lautet

>       Anweisung1 if Ausdruck2

> Anweisung1 wird also ausgeführt, wenn Ausdruck2 wahr ist. Um also bei unserem Beispiel zu bleiben:

>       $zahl3 = $zahl1 - $zahl2 if $zahl1 >= $zahl2;

> Die Bedingungsüberprüfung wird meist in der ersten Form durchgeführt, hier müssen auch die entsprechenden geschweiften Klammern verwendet werden (im Gegensatz zu C). Außerdem bietet Perl neben der if-else Form auch noch eine Zwischenentscheidung in der Form if-elsif-else. Das könnte z.B. so aussehen:

>       if (erste Bedingung){
>         Aktion 1;
>       } elsif (zweite Bedingung){
>         Aktion 2;
>       } else {
>         Aktion 3;
>       }

> Dabei können beliebig viele `elsif` Anweisungen vorkommen.

> Um gegebenenfalls auch eine umgekehrte Formulierung zu erlauben, bietet Perl neben der if-Anweisung eine entprechende `unless` Anweisung an. Sie wird wie if verwendet und könnte auch mit if-not übersetzt werden. Auch die unless-Anweisung kann ein else enthalten, was den Wahrheitswert der Überprüfung einfach umdreht. Die folgenden beiden Beispiele sind also genau equivalent:

>       if ($i > 10) {
>         Anweisung1;
>       } else {
>         Anweisung2;
>       }
>       unless ($i > 10) {
>         Anweisung2;
>       } else {
>         Anweisung1;
>       }

> ### Schleifen mit while, until und for

> Um Wiederholungen von bestimmten Programmteilen zu ermöglichen, bietet Perl zwei kopfgesteuerte Schleifen an, die sich wiederum nur im logischen Wahrheitswert der Schleifenbedingung unterscheiden. Die von C her bekannte while Schleife hat die Form:

>       while (Bedingung) {
>         Anweisung1;
>         Anweisung2;
>       }

> Solange die im Schleifenkopf genannte Bedingung also wahr ist, solange werden die Anweisungen in den geschweiften Klammern wiederholt. Zu beachten ist, dass diese Schleife nicht zwangsläufig durchlaufen werden muß, wenn die Bedingung schon von vorneherein eben nicht wahr ist. Die entsprechende Form mit umgekehrtem Wahrheitswert lautet:

>       until (Bedingung) {
>         Anweisung1;
>         Anweisung2;
>       }

> Was einfach meint, solange die Bedingung nicht erfüllt ist, wird der Block wiederholt.

> Eine dritte Form der Schleife gibt es - wie unter C - mit der for-Schleife. Diese Schleife wird meist als Zählschleife realisiert. Die folgenden beiden Konstrukte sind absolut identisch:

>       Initialausdruck;
>       while (Bedingung) {
>         Anweisung1;
>         Anweisung2;
>         Incrementausdruck;
>       }
>       for (Initialausdruck;Bedingung;Incrementausdruck) {
>         Anweisung1;
>         Anweisung2;
>       }

> Um also etwa eine Schleife zu schreiben, die uns auf 10 zählt, schreiben wir:

>       for ($i=1;$i<=10;++$i) {
>         print "$i\n";
>       }

> $i wird also zunächst auf 1 gesetzt, dann eine Schleife solange durchlaufen, solange $i kleiner oder gleich 10 ist und in jedem Schleifendurchgang wird $i um eins erhöht.

> ### Die Listenschleife foreach

> Um Listen oder Arrays abzuarbeiten, gibt es in Perl eine extra Schleifenform. Sie hat die Aufrufform:

>       foreach $var (@Liste){
>         Anweisung1;
>         Anweisung2;
>       }

> Dabei hat die Variable $var in jedem Schleifendurchgang den Wert eines Listenelementes der in Klammern angegebenen Liste. Das folgende Fragment würde also jeweils die Namen ausgeben:

>       @liste=("Hans","Otto","Gabi","Peter");
>       foreach $name (@liste){
>         print "Das ist $name\n";
>       }

> Das Ergebnis wäre also

>       Das ist Hans
>       Das ist Otto
>       Das ist Gabi
>       Das ist Peter

> ## Datentypen

> Perl unterscheidet zwischen verschiedenen Datentypen. Im Gegensatzt zu anderen Sprachen ist diese Unterscheidung aber weniger geprägt von dem, was eine Variable enthält, also etwa Zahlen oder Wörter, sondern von dem, ob sie eine einzelne oder zusammengesetzte Variable ist.

> ### Skalare Variablen

> Skalare Variablen sind in Perl einfache (nicht zusammengesetzte) Variablen. Im Gegensatz zu anderen Programmiersprachen wie etwa C gelten auch Zeichenketten als skalare Daten. Eine skalare Variable kann also entweder Zahlen oder Zeichenketten enthalten. Dabei wird kein Unterschied zwischen Fließkommazahlen (float) und Ganzzahlen (int) gemacht, sie werden aus der Anwendersicht behandelt wie Zeichenketten. Intern arbeitet Perl mit allen Zahlenformaten als Fließkommazahlen mit doppelter Genauigkeit (double).

> Skalare Variablen werden grundsätzlich mit einem Dollarzeichen angekündigt, das heißt, das erste Zeichen eines Variablennamens ist immer $.

> Die Angabe von Zahlen kann in nahezu jedem Format erfolgen. Bei Fließkommazahlen wird ein Punkt als Dezimaltrenner benutzt. Folgende Angaben sind gültige Zahlenangaben:

> Fließkommazahlen:
> `3.1415` | Drei Komma Eins Vier Eins Fünf
> `1.23e12` | Eins Komma Zwei Drei mal Zehn hoch Zwölf
> `-1.23e12` | Minus Eins Komma Zwei Drei mal Zehn hoch Zwölf
> `-1.23E-12` | Minus Eins Komma Zwei Drei mal Zehn hoch Minus Zwölf
> Ganzzahlen
> `123` | Hundertdreiundzwanzig
> `-123` | Minus Hundertdreiundzwanzig
> `0173` | Hundertdreiundzwanzig in oktaler Darstellung (Führende Null)
> `0x7b` | Hundertdreiundzwanzig in hexadezimaler Darstellung (Führendes 0x)

> Zeichenketten in Perl werden auf zwei unterschiedliche Weisen dargestellt. Entweder in einfachen Hochkommas (single-quoted string - `'...'`) oder in Anführungszeichen (double-quoted string - `"..."`). Der Unterschied ist der, dass innerhalb eines Strings in einfachen Hochkommas fast keine Interpretation enthaltener Sonderzeichen stattfindet. Jedes Zeichen, auch ein Zeilentrenner, der die Angabe des Strings über mehrere Zeilen hinweg ermöglicht, wird genauso gewertet, wie angegeben. Der einzige Punkt, an dem eine Interpretation in einem single-quoted string stattfindet, ist der Fall, wenn einem Backslash ein weiterer Backslash oder ein Hochkomma folgt. In dem Fall wird ein Backslash bzw. ein Hochkomma als Zeichen im String angenommen.

> Zeichenketten in Anführungszeichen werden interpretiert. Das heißt, dass sowohl Variablennamen, als auch Sonderzeichendarstellungen mit Backslash innerhalb der Zeichenkette interpretiert werden. Folgende Backslash-Sonderzeichen gelten in double-quoted Strings:

> Zeichen | Bedeutung
> --- | ---
> `\n` | Zeilentrenner (Newline)
> `\r` | Return
> `\t` | Tab
> `\f` | Seitenvorschub (Formfeed
> `\b` | Backspace
> `\v` | Vertikaler Tabulator
> `\a` | Alarm
> `\e` | Escape
> `\007` | Jeder beliebige oktale Wert (hier 007=Alarm)
> `\x7f` | Jeder beliebige hexadezimale Wert (hier 7f=Delete)
> `\cC` | Jedes beliebige "Control" Zeichen (hier Control-C)
> `\\` | Der Backslash selbst
> `\"` | Das Anführungszeichen
> `\l` | Nächstes Zeichen in Kleinbuchstaben (lowercase) darstellen
> `\L` | Alle nächsten Zeichen bis zum nächsten `\E` in Kleinbuchstaben darstellen
> `\u` | Nächstes Zeichen in Großbuchstaben (uppercase) darstellen
> `\U` | Alle nächsten Zeichen bis zum nächsten `\E` in Großbuchstaben darstellen
> `\E` | Beendet `\L` oder `\U`

> ### Zusammengesetzte Variablen

> Praktisch alle Programmiersprachen unterstützen die Verwendung zusammengesetzter Variablen gleichen Typs. In der Regel werden diese Variablentypen "ARRAY" genannt. Perl kennt zwei verschiedene Typen von Arrays, das normale und das assoziative Array. Ein normales Array wird in Perl durch einen Klammeraffen (@) vor dem Variablennamen gebildet. Ein kleines Beispiel:

>       @namen=("Hans", "Peter", "Gabi", "Otto");

> Das Array @namen besteht aus vier Elementen, die wiederum einfache skalare Variablen sind. Der Klammeraffe vor dem Arraynamen legt fest, dass es sich um ein Array handelt. Um wieder auf die einzelnen Elemente des Arrays zuzugreifen benutzen wir aber wieder das Dollarzeichen:

>       print "$namen[0]\n";

> würde uns also den Namen Hans auf dem Bildschirm ausgeben (Arrays zählen immer von 0 an). Normale Arrays werden also als nummerierte Listen behandelt, deren erstes Element die Nummer 0 besitzt, das zweite 1 usw.

> Im Gegensatz dazu bietet Perl auch die Möglichkeit sogenannter assoziativer Arrays an. In diesem Fall besteht das Array aus Paaren von skalaren Variablen, von denen jeweils das erste Element als Referenz für das zweite dient. Wollen wir z.B. das Alter von verschiedenen Personen speichern, so könnten wir das mit einem solchen assoziativen Array folgendermaßen erledigen:

>       %alter=("Hans", 37, "Peter", 45,  "Gabi", 23, "Otto", 19);

> Wir können jetzt mit einer Konstruktion wie

>       $alter{"Gabi"}

> auf den entsprechenden Wert (hier 23) zugreifen. Allerdings ist hier zu beachten, dass wir die Anführungszeichen innerhalb eines print-Befehls mit Backslash ausklammern, sonst kommt es zu Fehlern:

>       print "$alter{\"Gabi\"}\n";

> Alternativ dazu hätten wir für die innere Klammerung (des Strings "Gabi") auch einfache Hochkommas verwenden können:

>       print "$alter{'Gabi'}\n";

> Diese Form des Arrays erfreut sich in Perl großer Beliebtheit, da es einen wesentlich flexibleren Umgang mit Arrays ermöglicht.

> ## Operatoren

> Perl bietet die typischen Operatoren für Variablen an, die auch von anderen Programmiersprachen her bekannt sind.

> ### Rechenoperatoren

> Um mit Zahlen zu rechnen bietet Perl folgende Operatoren an:

> Operator | Bedeutung
> --- | ---
> + | Addition
> - | Subtraktion
> * | Multiplikation
> / | Division
> % | Modulo (Restbildung einer Ganzzahldivision)
> ** | Potenz (2**3 bedeutet 2 hoch 3)

> Neben diesen normalen Rechenoperatoren gibt es noch die zusammengesetzten Zuweisungsoperatoren, die schon von C her bekannt sind. So bedeutet die Zeile

>       $a += 15;

> soviel wie

>       $a = $a + 15;

> Diese Operatoren können mit allen vier Grundrechenarten und Modulo durchgeführt werden. Genauso gibt es die Increment und Decrement Operatoren ++ und -- So bedeutet

>       $a++;

> genau das selbe wie

>       $a = $a + 1;

> Wie schon unter C gibt es den Unterschied, ob der Operator vor oder nach dem Operanden steht.

> ### Zeichenkettenoperatoren

> Eine große Stärke von Perl sind die Operatoren für Zeichenketten. Hier stehen uns zunächst einmal die folgenden beiden Operatoren zur Verfügung:

> Operator | Bedeutung
> --- | ---
> . | Der Punkt verknüpft zwei Zeichenketten zu einer. (`"Hans" . "Otto"` ergibt `"HansOtto"`)
> x | Das `x` wiederholt Zeichenketten. (`"Hans" x 3` ergibt `"HansHansHans"`)

> ### Vergleichsoperatoren

> Um verschiedene Variablen zu vergleichen (etwa in einer if-Anweisung) bietet Perl Vergleichsoperatoren an. Allerdings unterscheidet Perl hier zwischen Zeichenketten (Strings) und Zahlen. Zeichenketten werden nach ihrem ASCII-Wert von links nach Rechts sortiert, was bedeutet, dass "Adam" kleiner als "Berta" ist. Allerdings führt das auch dazu, dass die Zeichenkette "100" kleiner als "2" ist. Deswegen gibt es für Zahlen separate Operatoren:

> Vergleich | Zahlenvariable | Stringvariable
> --- | --- | ---
> Gleichheit | `==` | `eq` (equal)
> Ungleichheit | `!=` | `ne` (not equal)
> Kleiner als | `<` | `lt` (less than)
> Kleiner oder Gleich | `<=` | `le` (less or equal)
> Größer als | `>` | `gt` (greater than)
> Größer oder Gleich | `>=` | `ge` (greater or equal)

> Für Zeichenketten gibt es dazu noch die Möglichkeit, einen Vergleich mit einem regulären Ausdruck vorzunehmen. Dazu dienen die beiden Operatoren `=~` (passt auf Ausdruck) und `!~` (passt nicht). Die regulären Ausdrücke werden dabei - wie schon unter sed und awk - in Slashs geklammert. Die folgende Zeile vergleicht also, ob der Inhalt der Variable `$Name` mit "Hans" beginnt:

>       $Name =~ /^Hans/

> ### Ein- und Ausgabe

> In Perl ist die Eingabe von Daten - ähnlich wie in C - zunächst einmal eine Dateioperation. Eine Eingabe von der Tastatur ist eigentlich nichts weiter als eine Eingabe aus der Datei STDIN (Standard-Eingabe). Diese Datei ist grundsätzlich zum Lesen geöffnet, steht uns also sofort zur Verfügung. Die Methode, wie wir diese Eingabe anwenden ist sehr einfach. Wir weisen einfach einer skalaren Variablen den Wert <STDIN> zu. Dadurch wird die nächste komplette Zeile der Standard-Eingabe einschließlich des Zeilentrenners in die Variable eingelesen.

> Die Ausgabe kann - wie ganz oben schon gesehen - über die `print` Funktion erledigt werden.