Studieren in Chemnitz. Wissen, was gut ist.






Perl in der Praxis

Frank Richter, URZ, Januar 2008

Historie und Eigenschaften

Entwickelt seit Ende der 80er Jahre von Larry Wall (u.a. patch, rn)

Ergebnis: Perl - Practical Extraction and Report Language

Großer Funktionsumfang:

Eingesetzt z.B. in

Konkurrenz:

Interpreter-Sprache:

Dokumentation und Literatur

Linux - englisch:

WWW - englisch:

Bücher - deutsch:

Formalitäten

Aufruf

perl -v Version
perl -w Skript Ausgabe von Warnungen - empfohlen!
perl -c Skript Syntax-Prüfung
perl -d Skript Debugger
perl -h weitere ...

Variablen (1)

Skalar genau ein Wert: Zahl, Zeichenkette $name
Array Liste von Werten, indiziert durch ganze Zahl @feld
Hash Liste von Werten, indiziert durch Zeichenkette (Assoziativfeld) %hash

use vars qw($zaehler @array);   # Deklaration von globalen Variablen
$zaehler = 0;                   # Initialisierung
@array = ();

Skalare

Immer $-Zeichen: bei Wertzuweisung und bei Zugriff auf Wert.

Zahlenwerte

$int = 123;          # ganze Zahl
$oktal = 040;        # Oktal, = 32 dezimal
$hexadezimal = 0x42; # Hexadezimal, = 66 dezimal
$float = 4.56;       # Dezimalbruch mit Punkt
$_12 = 12E-5;        # Exponentialdarstellung: "12 mal 10 hoch -5" = 0.00012

Arithmetische Operationen:

Numerische Vergleiche:

Mathematische Funktionen:

Bitoperationen (ähnlich C): print 0x10 << 2 | 2;

Viele mathematische Zusatz-Module:

Zeichenketten

$string1 = '456';                 # Keine Substitution, außer \' = ', \\ = \
$string2 = "Hallo $string1!\n";   # Doppel-Apostroph: Variablen-Substition, \-Sonderzeichen
print "\e[38m Roter Text\e[0m\n"; # Escape-Sequenz
$html = <<END;                    # sog. Here-Dokument
<html><head>
 <title>$string2 ...
END
Automatische Konvertierung: $summe = $int + $string;        # 579

Zeichenketten-Operatoren:

Vergleichsoperatoren: eq - gleich, ne - ungleich: if ($string1 eq $string2) {...}

Vielzahl von Zeichenketten-Funktionen:

  $laenge = length($trenner);           # 80
  print lc($string2);                   # Kleinschreibung, uc = Großschreibung
  print ucfirst('gross und Stark');     # nur erster Buchstabve groß: Gross und Stark
  chomp($zeile);                        # entfernt abschließendes Newline
  $teil = substr('26 Juni 2007', 3, 4); # Teilzeichenkette: Juni
  substr($teil, 2, 1) = 'l';            # Ersetzen: Juli

Ausgabe / Formatieren:

$fahrenheit = 20;
$celsius = ($fahrenheit - 32) * 5 / 9;

print "$fahrenheit F = $celsius C\n";
# Besser: gerundet auf eine Nachkommastelle
printf("%d F = %5.1f C\n", $fahrenheit, $celsius);

Reguläre Ausdrücke:

Spezial-Variablen, z.B.:

Datei-Testoperationen

-f name Name ist "normale Datei" if (-f $tmpname)
-d name Name ist Verzeichnis if (-d '/var/log' )
-r name Name ist lesbar if (-r '/var/log/messages')
-w name Name ist schreibbar if (-w '/etc/passwd') # Oha!
-s name Größe einer Datei in Bytes print -s '/etc/group';
Weitere: http://www.tu-chemnitz.de/docs/perldoc-html/functions/-X.html

Logische Operatoren

if ($a > 0 && $a <= 100)          # $a zwischen 1 und 100 (inkl.), auch and
if ($s eq 'y' || $s eq 'j')       # $s gleich y oder j, auch or
if (! $s)                         # $s ist leer oder Null

Bedingte Anweisungen: $a < 10 && print "$a kleiner 10\n";

Weitere Operatoren: http://www.tu-chemnitz.de/docs/perldoc-html/perlop.html

Steueranweisungen

Verzweigungen

if (Bedingung) {
   # Anweisungen: wenn Bedingung wahr
} elsif (andere Bedingung) {
   # Anweisungen: wenn andere Bedingung wahr
} else {
   # sonst diese Anweisungen
}

Bedingung = logischer Ausdruck:

Bedingte Anweisung: print "$a kleiner 10\n" if ($a < 10);

Bedingungsoperator ? - wie in C:

if (0) {
 ... nicht abgearbeiteter, aber interpretierter Kode - Syntax muss stimmen!
}

Schleifen

while (Bedingung) {        # Solange Bedingung wahr ist
   ...
}

until (Bedingung) {        # Solange Bedingung nicht wahr ist
   ...
}

do {
} while (Bedingung);

Auch hier bedingte Anweisungen:

Zählschleife

for (Initialisierung; Abbruchbedingung; Operation) {
   ...
}
z.B. Zinsberechnung:
$guthaben = 1000;
for ($jahr = 1; $jahr <= 10; $jahr++) {
    $guthaben += $guthaben * 0.05;    # Zins 5 %
    printf "Jahr %2d: %8.2f\n", $jahr, $guthaben;  # runden
}

Schleife über eine Liste: foreach $var (liste) { ... }

foreach $stadt ('Leipzig', 'Dresden', 'Chemnitz') {
    print "$stadt\n";
}

Sprungbefehle

# Listet Dateien im aktuellen Verzeichnis mit Größe
foreach $file (<*>) {       # file globbing liefert Datei-Liste lt. Shell-Muster: *, ?, []
    next if (! -f $file);   # überspringen, wenn keine normale Datei
    $size = -s $file;
    print "$file\t$size\n"; 
}
# Das Ganze sehr kompakt - die Standardvariable $_ kommt ins Spiel
foreach (<*>) { -f && print "$_\t", -s, "\n"; }

Variablen (2)

Arrays

Initialisierung:

Zugriff:

Funktionen:

Beispiel: Argumente der Kommandozeile via @ARGV

$usage = "$0 datei1 datei2 ...";

if ($#ARGV <= 1) {
    die "Aufruf: $usage\n";
}
while (@ARGV) {    # alle Argumente
   $datei = shift @ARGV;
   # ...
}

Hashes - Assoziativfelder

Initialisierung:
          %telefon2 = ('Meier' =>   { 'work' => '1234', 'home' => '4321'},
                       'Mueller' => { 'work' => '1234', 'home' => '4321'}
                      );

Zugriff:

Funktionen:

Beispiel: Gib kompletten Hash aus:

foreach $name (keys %telefon) {
    print "Name: $name\tTelefon: $telefon{$name}\n";
}
# Besser: sortiert, mit Überschrift
print "Name\tTelefon\n";
foreach $name (sort keys %telefon) {
    print "$name\t$telefon{$name}\n";
}
# Jetzt: Sortiert nach Wert
print "Telefon\tName\n";
foreach $name (sort {$telefon{$a} cmp  $telefon{$b}} keys %telefon) {
                                # cmp ist alphabetischer Vergleichsoperator
                                # <=> ist numerischer Vergleichsoperator
    print "$telefon{$name}\t$name\n";
}

Zugriff auf Umgebungsvariablen via %ENV

$home = $ENV{'HOME'};        # Lesen
$ENV{'PATH'} .= ':.';        # Setzen

Referenzen (Zeiger)

$zeiger_s = \$s;
$zeiger_a = \@array; 
$zeiger_h = \%hash;
$zeiger_f = \&funktion;

if ($$zeiger_s < 0) ...           # auch ${$zeiger_s}

@kopie = @$zeiger_a;              # Kopie des Arrays, auf das $zeiger_a zeigt
$first = $$zeiger_a[0];           # oder $zeiger_a->[0];
$last  = $$zeiger_a[$#$zeiger_a]; # oder $zeiger_a->[$#$zeiger_a];

$wert  = $$zeiger_h{'key'};       # oder $zeiger_h->{'key'};         

&$zeiger_f(1,2);                  # oder $zeiger_f->(1,2);

Umgang mit Dateien

Lesen

  • Schließen: (sonst erst automatisch bei Programmende)
    • close F;
    • close F or warn "Fehler beim Schliessen: $!\n"   # mit Warnung bei Fehler

  • Vordefinierter Dateizeiger: <STDIN> - Eingabe (i.A. Tastatur)
    • $eingabe = <STDIN> # liest eine Zeile von Tastatur

# Datei ausgeben mit Zeilennummer:
print "Datei: ";
$datei = <STDIN>;  # Abfrage via Eingabe
chomp $datei;      # Newline am Ende wegschneiden
open F, $datei or die "Kann $datei nicht oeffnen: $!\n";
while (<F>) {
    # Ohne Variable --> verwende Standard-Variable $_
    print $., ' ', $_;       # $. = aktuelle Zeilennummer
}

  • Wenn Skript eine oder mehrere Datei(en), die auf der Kommandozeile angeben sind, oder Daten der Eingabe bearbeiten soll:
while ($zeile = <>) {
    print lc($zeile);      # alles in Kleinbuchstaben wandeln und ausgeben.
}
# Kurzform
while (<>) {       # Standard-Variable $_ verwenden
    print lc;      # Auch lc verwendet Standard-Variable ...
}

Schreiben

  • Öffnen:
    • open S, '> dateiname' - öffnet dateiname zum (Über-)Schreiben
    • open S, '>> dateiname' - Daten werden hinten angehangen

  • Schreiben via Dateizeiger:
    • print S "eine Zeile\n"; # eine Zeile
    • printf S "%d\t%s\n", $zahl, $string;

  • Schließen wie gehabt: close S;
# Neue Datei ausgeben mit Zeilennummern:
print "Datei: ";
$datei = <STDIN>;  # Abfrage via Eingabe
chomp $datei;      # Newline am Ende wegschneiden
open LIES, $datei or die "Kann $datei nicht oeffnen: $!\n";
open SCHREIB, "> $datei.num" or die "Kann $datei.num nicht zum Schreiben oeffnen: $!\n";
while (<LIES>) {
    print SCHREIB $., ' ', $_;       # $. = aktuelle Zeilennummer
}
close SCHREIB;
close LIES;
print "Datei $datei.num geschrieben.\n";

Funktionen zum Dateisystem

mkdir dir, mode Verzeichnis anlegen -d '/tmp/test' or mkdir '/tmp/test', 0755;
chmod mode, file Rechte ändern chmod 0750, 'dada';
unlink file Datei löschen unlink <*.bak>;

viele weitere

Aufruf von externen Programmen

  • system(kommando) führt kommando aus, mit Ausgabe, liefert exit-Status:
if (system("ls -l $dir") != 0) {
    print "Fehler bei Aufruf: $?\n";
}

  • `...` (Backtick wie Shell) oder qx(...) gibt Kommandoausgabe zurück: $etc =`ls -l /etc`;

Pipes

Lesen:

  • open PROG, "command |" or die "Kann command nicht starten: $_\n";

Schreiben:

  • open P, "| command" or die "Kann command nicht starten: $_\n";

# Transparentes Behandeln evtl. komprimierter Dateien
if ($datei =~ /\.gz$/) {   # dateiname mit .gz am Ende
    open F, "zcat $datei |" or die "Kann zcat nicht starten: $!\n";
} else {
    open F, $datei or die "Kann Datei nicht oeffnen: $!\n";
}
while (<F>) { ... }
close F;

Aufruf von Perl-Kode

eval Perl-Kode - führt Perl-Kode in eigenem Interpreter aus

  • z.B. zum Umgehen des Programmabbruchs bei Division durch 0
    eval { $resultat = $a / $b; }; warn $@ if $@;
  • "Breakpunkt" während Entwicklung: eval <STDIN>;

# Mini-Taschenrechner
do {
    print "Rechner: ";
    chomp($in = <STDIN>);
    $res = eval $in;
    if ($@) {   # Fehler von eval
        print "Ungueltige Eingabe\n";
    } else {
        print "Ergebnis: $res\n";
    }
} while ($in);

Funktionen

Definieren:
  • sub funktionsname { ... }
  • Argumente via @_ - Standard-Array
  • Rückgabe via return value
  • Lokale Variablen: my $var;
  • Rekursion möglich

sub summe2 {
    my ($a, $b) = @_;
    return $a + $b;    
}
sub summe {      # beliebige Anzahl der Argumente
    my $s = 0;
    foreach (@_) { $s += $_; }
    return $s;
}

Aufruf:

  • &funktionsname(argumente ...);
  • neuerdings auch ohne &
  • Reihenfolge Definition / Aufruf egal
print summe(1..1000), "\n";

Argumente per Referenz (Zeiger):

@grossdatei = <F>;          # gesamte Datei in array
&work(\@grossdatei);

sub work {
    my ($aref) = $@;
    print $aref->[0]; ...
}

Signalbehandlung:

  • Signal (z.B. durch Drücken von ^C) an ein Perl-Skript während der Ausführung führt normalerweise zum Abbruch.
  • Dies kann gesteuert werden, entweder um manche Signale zu ignorieren oder um vorm Abbruch noch Aktionen auszuführen.
  • Hash %SIG enthält als Schlüssel die Namen der Signale, z.B. INT für Interrupt-Signal (^C).
    Als Werte sind möglich:
    • DEFAULT = Abbruch
    • IGNORE = Kein Abbruch, Signal wird nicht beachtet
    • \&func = funktion func wird aufgerufen.

# Bei ^C soll eine temporäre Datei gelöscht werden, danach wird beendet.
$SIG{'INT'} = \&tmpdatei_loeschen;
...
sub tmpdatei_loeschen {
    unlink '/tmp/temp_datei';
    exit;
}

Reguläre Ausdrücke

  • beschreiben Muster von Zeichenketten, z.B. "Eine ID-nummer und eine Beschreibung" -> "vier Ziffern, gefolgt von beliebig vielen Leerzeichen, danach beliebige Zeichen außer Ziffern"
  • Zum Filtern (und Ersetzen) von bestimmten Daten aus einem "Datenstrom"
  • auch in anderen Linux-Programmen: awk, sed, grep, vim, ...

Bindungs-, Matchoperator und Ersetzungsoperator:

  • $string =~ m/reg. Ausdruck/;
  • Wenn "Trenner" / ist, kann m auch weggelassen werden, mit m beliebiger Trenner möglich
  • $string =~ s/reg. Ausdruck/Ersetzung/; - auch hier: beliebige Trenner

print "Abbruch? ";
chomp($eingabe = <STDIN>);
exit if ($eingabe =~ /j/);        # eingabe enthält j

if ($dateiname !~ m#/#) { ... }   # dateiname enthält KEIN /

while (<>) {
    print if (/Subject:/);        # aktuelle Zeile enthält Subject:
}

Aufbau von Mustern

"Joker" für einzelne Zeichen:

Muster-Zeichen Bedeutung Beispiel Erläuterung
. ein beliebiges Zeichen /M.st/ Mast, Mist, Most, aber auch M8st, aber nicht Morast
[abc] oder [0-9] ein Zeichen aus einer Gruppe /M[aio]st/ Mast, Mist, Most
[^A-Z] ein Zeichen nicht aus dieser Gruppe /M[^a]st/ nicht Mast
\d bzw. \D eine Ziffer bzw. ein Zeichen, aber keine Ziffer / \d\d:\d\d / "Leer, 2 Ziffern, :, 2 Ziffern, Leer"
\w bzw. \W ein Wortzeichen [0-9A-z_], bzw. kein Wortzeichen    
\s bzw. \S ein Leerzeichen [ \t\n\f\f] bzw. kein Leerzeichen    
\ hebt Sonderzeichen auf /datei\.html/ Sonderbedeutung von . aufgehoben

Quantifizierer - wie oft ein Zeichen oder eine Zeichenklasse?

Muster-Zeichen Bedeutung Beispiel Erläuterung
* vorheriges Zeichen/Muster beliebig oft, auch gar nicht /M.*st/ Mast, ..., auch Morast, aber auch Mst
+ vorheriges Zeichen/Muster mindestens einmal /\d+\s+/ eine Zahl, gefolgt von mind. einem Leerzeichen
? vorheriges Zeichen/Muster einmal oder gar nicht /Jan 0?\d/ Datum vom 1. bis 9. Januar, egal ob führende 0
{n} vorheriges Zeichen/Muster genau n Mal / \d{4} / eine vierstellige Zahl in Leerzeichen
{m,n} vorheriges Zeichen/Muster m bis n Mal / [a-z]{3,8} / drei- bis achtstellige Kleinbuchstabenfolge
{m,} vorheriges Zeichen/Muster mindestens m Mal / \w{8,} / Wörter mit mind. 8 Zeichen

  • matchen normalerweise "gefräßig" (greedy), so viele Zeichen, wie sie ins Muster passen
  • minimales Matchen durch Anhängen von ? an Quantifizierer
$htmltitel = '<title>Perl-Zauberei</title>';
$text = $text1 = $text2 = $htmltitel;
$text  =~ s/<.+>//;       # ersetze alles zwischen < und > durch nichts
$text1 =~ s/<.+?>//;      # das gleiche, nur "nicht gefräßig"
$text2 =~ s/<.+?>//g;     # das gleiche, nur "nicht gefräßig" und beliebig oft

print "$text\n$text1\n$text2\n";

Verankerung:

Muster-Zeichen Bedeutung Beispiel Erläuterung
^ Anfang der Zeichenkette m#^/# beginnt mit /
$ Ende der Zeichenkette /\.html$/ endet mit .html
\b bzw. \B Wortgrenze (Anfang oder ende) bzw. keine Wortgrenze /\bftp\b/ "Wort" ftp, aber nicht Luftpumpe

Gruppierung, Alternativen, Variablen:

Muster-Zeichen Bedeutung Beispiel Erläuterung
(muster) Zeichen gruppieren /(\d+\.\d+;){5}/ fünf durch Semikolon getrennte Kommazahlen
(muster1|muster2) Alternativen /(Jan|Feb|Mar)/ Jan, Feb oder Mar
$var bzw. ${var} Variable, wird ersetzt durch Wert    

Quotierung - Sonderzeichen flüchten:

  • Bei allen Sonderzeichen, die als normale Zeichen behandelt werden sollen, muss \ vorangestellt werden:
    if ($var =~ /\[\w{3}\]/) # [...]
  • Bei vielen: $klammern = quotemeta '()[]{}'; if ($ausdruck =~ /$klammern/) ...
  • Bei Verwendung von Variablen kann regulärer Ausdruck ungültig werden - hier flüchten mit \Q...\E:
    if ($zeile =~ /\Q$eingabe\E/) ...

Rückbezug (Backreferencing)

Auf durch Klammern zusammengefasste Teile kann wieder Bezug genommen werden: (muster)...\1

  • im regulären Ausdruck: /(muster)...\1/, z.B. /(\d)\1/ passt auf 11, 22, ...
  • beim Ersetzen: s/...(muster).../$1/, z.B.
    $datum =~ s/\b([A-Z][a-z]{2}) (\d{2})\b/$2. $1/; # Datum umformen: Jan 13 -> 13. Jan
  • später /...(muster).../; $var = $1;, z.B. if ($zeile =~ /\b([A-Z][a-z]{2})\b/) { $monat = $1; }

# Palindrome mit vier Buchstaben, z.B. ANNA
if (open(F, '/usr/share/dict/words')) {
    while (<F>) {
        $l = lc;                              # Zeile in Kleinbuchstaben
        print if ($l =~ /^(\w)(\w)\2\1$/);    # zwei Zeichen, dann 2. Zeichen und wieder 1. Zeichen
    }
}

Modifizierer

  • beeinflussen das Verhalten
  • werden hinten angefügt, hinter das letzte Trennzeichen, z.B. if (/error/i) { ... }
  • mehrere Modifizierer einfach hintereinander schreiben

Modifizierer Bedeutung Beispiel Erläuterung
g global, d.h. suche/ersetze alle Vorkommen des Musters $a = 'abba'; $a =~ s/a/e/g; -> ebbe, ohne g: ebba
i ignoriere Groß-/Kleinschreibung if (/error/i) findet error, Error, ERROR, ...
s single line, . passt auch auf \n    
m multi-line, ^ und $ passen auf Beginn/Ende jeder Zeile    
e eval - nur bei Ersetzen: der Ersetzungsteil wird als Perl-Ausdruck ausgewertet s/(\d+)/$1*10/ge; Ersetze Zahlen durch ihr Zehnfaches
x extended - Kommentare und Leerzeichen/Zeilumbrüche im Muster erlaubt s/(\d+) # Zahl/$1*10/gex;  

Beispiel: Wörter zählen

while (<>) {                 # Für jede Zeile 
     while (/(.+?)\s+/g) {   # mind. 1 beliebiges Zeichen bis Leerzeichen, 
                             # minimal matchen, merken, alle Vorkommen
         $c++;
     }
}
printf "$c %s\n", $c == 1 ? 'Wort' : 'Woerter';

Erweiterte reguläre Ausdrücke

Siehe http://www.tu-chemnitz.de/docs/perldoc/perlre.html#Extended-Patterns

Reguläre Ausdrücke in split

z.B. Aufsplitten an beliebigen Leerzeichen: @teile = split(/\s+/, $zeile);

Beispiel: Auswertung Apache-Log-Datei

Common Log Format (CLF), in httpd.conf: LogFormat "%h %l %u %t \"%r\" %>s %b" common
z.B.

# Klient      - user Datum       Zeit            Request                     Status Bytes
134.109.200.2 - fri [15/Jan/2008:13:55:36 +0100] "GET /apache_pb.gif HTTP/1.0" 200 2326

Ein möglicher regulärer Ausdruck: ^\S+ - \w+ \[.+?\] "\S+ \S+ \S+" \d+ \d+

while (<>) {    # zeilenweise für alle Dateien der Kommandozeile
    #     Klient  user    Datum/Zeit      Dokument   Status Bytes
    if (/^(\S+) - (\S+) \[(\S+) .+\] "\S+ (\S+) \S+" (\d+) (\d+)/) {
        $bytes += $6;       # Bytes summieren
        $HOSTS{$1}++;       # Hostzugriff merken
    } else {
        print STDERR "Fehler: $_";
    }
}
# Auswertung:
print "Daten: $bytes Bytes\n\n";
# Sortieren: Welcher Klient hat am meisten geholt:
print "Zugriffe : Klient\n";
foreach $h (sort {$HOSTS{$b} <=> $HOSTS{$a}} keys %HOSTS) {
    printf "%8d : %s\n", $HOSTS{$h}, $h;
}

Umgang mit Zeichensätzen

  • Nationale Sonderzeichen, z.B. Umlaute, sind in verschiedenen Zeichensätzen festgelegt, z.B. ISO-8859-1 = Latin1
  • Müssen von Zeichenkettenfunktionen und regulären Ausdrücken beachtet werden.

# Beispiel für Arbeit mit Umlauten im ISO-8859-1-Zeichensatz = Latin1

# seit perl 5.8: Daten sind Latin1, Bildschirmausgabe aber UTF-8-Zeichen
use encoding latin1, STDOUT => "utf8";

# Hier ISO-8859-1 kodiert:
$umlaute = 'Umlaute sind äöüÄÖÜ(ß)';

#      z.B. \w umfasst auch Umlaute
($entfernt = $umlaute) =~ s/\w+//g;

print "Normal: $umlaute" .
      "\nGross:  " . uc($umlaute) .
      "\nKlein:  " . lc($umlaute) .
      "\nEntfernt: .$entfernt.\n";

  • Unterstützung für Unicode seit Perl 5.6, ab 5.8 richtig
  • Praktisch ist Kodierung UTF-8 interessant.
  • Problem: ein Zeichen ist mglw. länger als ein Byte
    -> Anpassung für Zeichenkettenfunktionen und reguläre Ausdrücke

#!/usr/bin/perl
# Beispiel für Arbeit mit Umlauten: UTF-8 kodiert

use encoding 'utf8';     # seit Perl 5.8
# use utf8;              # nur nötig, wenn z.B. auch Variablennamen UTF-8 einhalten
use open ':utf8';        # zu öffnende Dateien enthalten UTF-8-Daten
  
# Hier UTF-8 kodiert:
$umlaute = 'Umlaute sind äöüÄÖÜ(ß)';

($entfernt = $umlaute) =~ s/\w+//g;     # \w umfasst auch UTF-8-Zeichen

print "Normal: $umlaute" .
      "\nGross:  " . uc($umläute) .
      "\nKlein:  " . lc($umläute) .
      "\nEntfernt: .$entfernt.\n";

Verwendung von Modulen

  • Viele Module für Standard-Aufgaben sind in der Standard-Installation enthalten.
  • hierarchisch: Gruppe::Modul, z.B. File::Copy
  • Listet installierte Module: perldoc perlmodlib
  • Dokumentation zu Modul: perldoc Modulname, z.B. perldoc CGI
  • Tausende Module via http://www.cpan.org

Verwendung:

  • use Modulname; - alle Funktionen importieren
  • use Modulname qw(func1 func2); - nur bestimmte Funktionen
  • einmalig externe Datei laden (wie #include in C): require 'Dateiname';

Beispiel: Programmargumente mit Optionen verarbeiten:

use Getopt::Std;
# Aufruf:  perlskript [-d] [-o datei]
getopts('do:');         # -d ohne Argument, -o mit Argument

$debug = $opt_d;        # 1, wenn -d vorhanden
if ($opt_o) {           # Wenn -o vorhanden
    $output = $opt_o;   # verwende Wert
}
...

Mehr: perldoc Getopt::Std; perldoc Getopt::Long

Objekte und Klassen

  • Klassen werden als package realisiert (in Modulen)
  • Objekte werden über Konstruktor erzeugt: $obj = Class->new();
  • So auch Methoden: $obj->methode();
  • Zugriff auf Objekt-Attribute: $obj->{attr};

Mehr: http://www.tu-chemnitz.de/docs/perldoc/perlobj.html

Beispiel: Kleine Oberfläche mit Modul Tk

use Tk;
my $fenster = MainWindow->new;      # Hauptfenster erzeugen
$fenster->geometry('300x150');      # Größe

# Ein Knopf mit Aktion
$fenster->Button(-text => 'Hallo Welt!', -command => \&action)->pack();

# "Warteschleife"
MainLoop;

sub action { print "Hallo Du!\n"; exit; }

Webprogrammierung

CGI-Programme (Common Gateway Interface) für dynamische WWW-Seiten:
  • WWW-Browser fordert via HTTP Daten ab
  • WWW-Server startet Perl, führt Skript aus und übergibt ggf. Daten
  • Skript führt Aktionen aus (z.B. Datenbank-Abfrage) und gibt HTML-Seite aus
  • WWW-Server schickt diese an Browser

#!/usr/bin/perl
# erstes CGI-Skript - ohne CGI.pm

print "Content-Type: text/html\n\n";

print <<HTML;
<html><head><title>Mein erstes CGI-Skript</title></head>
<body>
<h1>Hallo Welt!</h1>
</body>
</html>
HTML

  • Skript in Webspace kopieren, für TU Chemnitz: Endung .cgi
  • Ausführbar: chmod +x script.cgi

Modul CGI definiert HTML-Abkürzungen, Hilfe zur Formularauswertung, Cookies etc., siehe perldoc CGI

#!/usr/bin/perl
# CGI-Skript - mit CGI.pm

use CGI qw(:standard);
print header,
      start_html('CGI-Skript mit CGI.pm'),
      h1('Hallo Welt!'), end_html;

Formulare und deren Auswertung via Funktion param()

#!/usr/bin/perl
# CGI-Skript mit einfachem Formular und Auswertung

use CGI qw(:standard);
use HTML::Entities 'encode_entities';   # Kodierung von HTML-Sonderzeichen
print header,
      start_html('Englisches W&ouml;rterbuch'),
      h1('Englisches W&ouml;rterbuch'),
      start_form,
      'Gesuchtes Muster: ', input({'name'=>'frage'}),
      submit,
      end_form,
      hr;

if (param()) {      # Sind Werte übergeben worden? = Formular abgeschickt
    my $suchwort = param('frage');   # Zugriff auf formularwert
    if ($suchwort) {
        print 'Suche nach ', encode_entities($suchwort);
        print pre(suche($suchwort));        # schreibe Ergebnisse in <pre>
    }
}
print end_html;

sub suche {
    my ($wort) = @_;
    my $ergebnis = '';
    if (! open F, '/usr/share/dict/words') { 
        return "Kann Datei nicht &ouml;ffnen: $!\n";
    }
    while (<F>) {
        $ergebnis .= $_ if (/\Q$wort\E/);  # Sonderzeichen flüchten
    }
    close F;
    $ergebnis =~ s#$wort#<b>$wort</b>#g;   # Suchwort fett markieren: <b>...</b>
    return $ergebnis;
}

Arbeit mit SQL-Datenbanken

Schnittstelle zu verschiedenen SQL-Darenbanken via Modul DBI, siehe perldoc DBI
#!/usr/bin/perl
# Beispiel zum Zugang zu MySQL-Datenbanken

use DBI;
# DB-Verbindung          Typ  Datenbank  Server             Login Passwort
$dbh = DBI->connect('DBI:mysql:events:www-db.tu-chemnitz.de', '', '')
   or die "Kann Datenbank-Verbindung nicht herstellen: $DBI::errstr\n";

# Abfrage vorbereiten
my $sth = $dbh->prepare('SELECT * FROM event WHERE startdate >= NOW() ORDER BY startdate LIMIT 5');

if ($sth->execute) {              # Abfrage starten
    # DBI::dump_results($sth);    # Zum Test "rohe" Ausgabe

    while (my $ref = $sth->fetchrow_arrayref) {     # Ergebnisse "abholen"
        print " Titel: $$ref[1]\nBeginn: $$ref[4]\n\n";
    }
}

$dbh->disconnect();         # DB-Verbindung beenden

Mehr: perldoc DBD::mysql