klicken - Centrum für Informations- und Sprachverarbeitung
Transcription
klicken - Centrum für Informations- und Sprachverarbeitung
Einführung in die Programmierung für Computerlinguisten Centrum für Informations- und Sprachverarbeitung, LMU München Dr. Maximilian Hadersbeck Mitarbeiter an der Erstellung des Skripts: Dokumentvorlage und LATEX-Spezialist: Daniel Bruder Konvertierung des Skripts nach LATEX: Ekaterina Peters Mitarbeit: Claudia Müller, Junhan Chen, Stefan Schätz, Nicola Greth — Version Wintersemester 2015/2016 — Inhaltsverzeichnis 1. Geschichte und Aufgaben der Informatik 1.1. Rechner der nullten Generation . . . . . . . . . . . 1.2. Rechner der ersten Generation 1946 – 1965 . . . . 1.3. Die Rechner der zweiten Generation 1957 – 1963 . 1.4. Rechner der dritten Generation 1964 – 1981 . . . . 1.5. Die Rechner der vierten Generation 1982-1989 . . . 1.6. Die Rechner der fünften Generation . . . . . . . . 1.7. Die Rechnergenerationen bis ca. 1990 im Überblick 1.8. Verwendete Abkürzungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 . 2 . 3 . 4 . 5 . 7 . 7 . 8 . 10 2. Die Programmiersprache Perl 2.1. Allgemeines zu Perl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2. Kurzübersicht zu Perl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3. Aufbau eines Perl Programms . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3.1. Das erste Perl-Programm . . . . . . . . . . . . . . . . . . . . . . . . 2.4. Start eines Perl Programms . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5. Editieren und Starten eines Perl - Programms mit dem UNIX Programm kate 2.5.1. Bemerkungen zur Syntax von Perl Programmen . . . . . . . . . . . 2.6. Datenstrukturen 1: Skalare und Listen . . . . . . . . . . . . . . . . . . . . . 2.6.1. Vorbemerkung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.6.2. Einfache Datenstrukturen: Skalare . . . . . . . . . . . . . . . . . . . 2.6.3. Zusammengesetzte Datenstrukturen: Listen . . . . . . . . . . . . . . 2.7. Variablen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.7.1. Deklaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.8. Ausdrücke . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.8.1. Wertzuweisung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.8.1.1. Zuweisung einer Konstanten . . . . . . . . . . . . . . . . . 2.8.1.2. Zuweisung eines Ausdrucks . . . . . . . . . . . . . . . . . . 2.8.2. Einlesen der Daten vom Terminal . . . . . . . . . . . . . . . . . . . . 2.9. Operatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.9.1. arithmetische Operatoren . . . . . . . . . . . . . . . . . . . . . . . . 2.9.2. string Operatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.9.3. Grundlagen: Logische Ausdrücke . . . . . . . . . . . . . . . . . . . . 2.9.4. Vergleichsoperatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.10. Kontrollstrukturen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.10.1. Blöcke . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.10.2. Auswahlanweisung: if . . . . . . . . . . . . . . . . . . . . . . . . . . 2.10.3. Auswahlanweisung: if...else . . . . . . . . . . . . . . . . . . . . . . . 2.10.4. Wiederholungsanweisung: while . . . . . . . . . . . . . . . . . . . . . 2.10.5. Wiederholungsanweisung: do while . . . . . . . . . . . . . . . . . . . 2.10.6. Wiederholungsanweisung: do...until . . . . . . . . . . . . . . . . . . . 2.10.7. Wiederholungsanweisung: foreach . . . . . . . . . . . . . . . . . . . . 2.10.8. Wiederholungsanweisung: for . . . . . . . . . . . . . . . . . . . . . . 11 11 11 12 12 13 13 14 15 15 15 15 16 17 18 19 19 19 20 23 23 23 23 24 27 27 28 28 29 31 31 32 32 i ii Inhaltsverzeichnis 2.11. Lesen von Daten aus einer Datei . . . . . . . . . . . . . . . . . . . . . . . 2.11.1. Dateihandles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.12. Interne Repräsentation von Zahlen . . . . . . . . . . . . . . . . . . . . . . 2.13. Interne Repräsentation von Schriftzeichen . . . . . . . . . . . . . . . . . . 2.13.1. Speicherung von Strings . . . . . . . . . . . . . . . . . . . . . . . . 2.13.2. Speicherung von Buchstaben . . . . . . . . . . . . . . . . . . . . . 2.13.3. Zeichencodierung: ASCII, für Buchstaben, mit 7 Bit . . . . . . . . 2.13.4. Bedeutung der Steuerzeichen . . . . . . . . . . . . . . . . . . . . . 2.13.5. Zeichencodierung: ISO Latin-1 für Buchstaben, 8 Bit . . . . . . . . 2.13.6. Zeichenkodierung nach den Vorgaben des UNICODE Konsortium . 2.13.7. Die UTF Prinzipien . . . . . . . . . . . . . . . . . . . . . . . . . . 2.13.8. Die UTF Kodierung im Detail . . . . . . . . . . . . . . . . . . . . 2.13.9. UTF-8 im Internet . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.13.10.UTF-8 Mode in Perl . . . . . . . . . . . . . . . . . . . . . . . . . . 2.14. Lesen der Daten vom Terminal mit utf8 Kodierung . . . . . . . . . . . . . 2.14.1. Standardein- und ausgabe beim Programmstart auf utf8 festlegen 2.14.2. Standardein- und ausgabe zur Laufzeit auf utf8 festlegen . . . . . 2.14.3. Lesen aus Dateien mit utf-8 Kodierung . . . . . . . . . . . . . . . . 2.15. Die spezielle Variable : $_ . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.16. Datenstrukturen 2: Hashes . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.16.1. Hash Operatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.16.2. Löschen von Einträgen im Hash . . . . . . . . . . . . . . . . . . . . 2.16.3. Zugriff auf den Hash . . . . . . . . . . . . . . . . . . . . . . . . . . 2.16.3.1. Zugriff auf alle Keys im Hash . . . . . . . . . . . . . . . . 2.16.3.2. Zugriff auf alle Werte im Hash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 34 36 38 38 38 39 39 40 43 44 44 46 46 48 49 49 50 51 53 54 54 54 54 54 57 57 57 58 58 58 59 59 59 59 60 60 60 61 62 63 63 3. Reguläre Ausdrücke in Perl 3.1. Buchstaben in einem regulären Ausdruck . . . . . . . . . . 3.2. Übersicht über Metazeichen . . . . . . . . . . . . . . . . . . 3.3. Metazeichen . = Wildcard . . . . . . . . . . . . . . . . . . . 3.4. Metazeichen [ ] = Buchstabenbereiche . . . . . . . . . . . . 3.5. Metazeichen * , + , ? { } = Quantifizierung . . . . . . . . . 3.6. Metazeichen ( ) = Zeichengruppierung . . . . . . . . . . . . 3.7. Metazeichen ˆ = Anfang der Zeile . . . . . . . . . . . . . . 3.8. Metazeichen $ = Ende der Zeile . . . . . . . . . . . . . . . . 3.9. Metazeichen \= Ausschalten der Metazeichenerkennung . . 3.10. Metazeichen [ˆ ] = negierte Buchstabenbereiche . . . . . . . 3.11. Buchstabenklassen ohne UNICODE . . . . . . . . . . . . . 3.12. Buchstabenklassen mit UNICODE . . . . . . . . . . . . . . 3.13. Zugriff auf gruppierte Teile des Regulären Ausdrucks . . . . 3.14. Globales Suchen in einer Zeile . . . . . . . . . . . . . . . . . 3.15. Ersetzen von Strings: substitute . . . . . . . . . . . . . . . . 3.16. Greedy-Nongreedy Verhalten bei Quantifizierung . . . . . . 3.17. Zugriff auf gruppierte Teile des regulären Ausdrucks beim Zeichenketten . . . . . . . . . . . . . . . . . . . . . . . . . . 3.18. Suchen über Zeilengrenzen hinweg . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ersetzen von . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4. Systemroutinen in Perl 4.1. Vorbemerkung . 4.2. split . . . . . . 4.3. ord . . . . . . . . 4.4. chr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 . 64 66 66 66 67 68 Inhaltsverzeichnis 4.5. length . 4.6. scalar . 4.7. join . . 4.8. pop . . . 4.9. push . . 4.10. shift . 4.11. unshift 4.12. reverse 4.13. sort . . iii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 68 69 69 70 70 71 71 72 5. Subroutinen in Perl 5.1. Definition von Subroutinen in Perl . . . . . . . . . . . . . . . . . . . . . . . 5.2. Datenaustausch zwischen Subroutinen und Hautpprogramm . . . . . . . . . 5.3. Zugriff auf die Argumentvariablen in Subroutinen . . . . . . . . . . . . . . . 5.3.1. Lokale Variablen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3.2. Gültigkeitsbereich von lokalen Variablen . . . . . . . . . . . . . . . . 5.3.3. Übergabe des Argumentwerts an eine lokale Variable in der Subroutine 5.4. Probleme bei der Übergabe von Argumenten an eine Subroutine . . . . . . 5.4.1. Übergabe der Argumentvariable als Referenz: . . . . . . . . . . . . . 5.4.2. Übergabe der Argumentvariablen als Referenz und Ändern des Wertes der Argumentvariable: . . . . . . . . . . . . . . . . . . . . . . . . 5.5. Rückgabewerte von Subroutinen . . . . . . . . . . . . . . . . . . . . . . . . 5.6. Globale Variablen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.6.1. Die Verwendung von our . . . . . . . . . . . . . . . . . . . . . . . . . 5.7. Rekursion bei Subroutinen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.8. Exkurs: Übergabemechanismus in Perl im Detail (für den Spezialisten) : . . 5.8.1. Der STACK Speicher bei Subroutinenaufrufen . . . . . . . . . . . . 5.9. Beispiel: Berechnung des Wochentags in Abhängikeit vom Datum . . . . . . 81 81 82 82 82 83 84 85 6. Aufgaben und Lösungen 6.1. Aufgabe: größte/kleinste Zahl . . . . . . . . . 6.2. Aufgabe: Alphabetischer Vergleich . . . . . . 6.3. Aufgabe: Fakultät (iterativ, rekursiv) . . . . . 6.4. Aufgabe: Einlesen einer Rechenaufgabe . . . . 6.5. Aufgabe: Wörter mit Selbstlauten extrahieren 6.6. Aufgabe: Buchstaben zählen . . . . . . . . . . 6.7. Aufgabe: Passwort abfragen . . . . . . . . . . 6.8. Aufgabe: Wörter mit drei Buchstaben . . . . 6.9. Aufgabe: Wörter zählen . . . . . . . . . . . . 6.10. Aufgabe: Split von Zeilen und Wortliste . . . 6.11. Aufgabe: Frequenzliste . . . . . . . . . . . . . . . . . . . . . . . . 89 89 89 90 91 92 92 93 94 94 95 96 . . . . . . . . 97 97 97 97 98 98 99 99 99 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7. Linux 7.1. Einführung in Linux . . . . . . . . . . . . . . . . . . . . . 7.1.1. Einleitung . . . . . . . . . . . . . . . . . . . . . . . 7.1.2. Eigenschaften . . . . . . . . . . . . . . . . . . . . . 7.2. Verwalten von Dateien Teil 1 . . . . . . . . . . . . . . . . 7.2.1. Einleitung . . . . . . . . . . . . . . . . . . . . . . . 7.2.2. Das Linux Dateisystem . . . . . . . . . . . . . . . 7.2.2.1. Der hierarchische Dateibaum . . . . . . . 7.2.2.2. Verzeichnisse, Dateien und Gerätedateien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 73 74 75 76 77 77 78 79 iv Inhaltsverzeichnis 7.3. 7.4. 7.5. 7.6. 7.2.3. Fallbeispiel zum Verwalten von Dateien . . . . . . . . . . . . . . . 7.2.3.1. Das Anlegen von Dateien . . . . . . . . . . . . . . . . . . 7.2.3.2. Das Anzeigen von Inhaltsverzeichnissen . . . . . . . . . . 7.2.3.3. Länge und Zeichenkonventionen von Dateinamen . . . . . 7.2.3.4. Das Löschen von Dateien . . . . . . . . . . . . . . . . . . 7.2.3.5. Das Anzeigen von Dateien . . . . . . . . . . . . . . . . . 7.2.3.6. Das Verwalten von Verzeichnissen . . . . . . . . . . . . . 7.2.3.7. Das Kopieren und Umbenennen von Dateien . . . . . . . 7.2.4. Dateinamen und der Einsatz von Wildcards . . . . . . . . . . . . . 7.2.4.1. Einsatz von Wildcards . . . . . . . . . . . . . . . . . . . . 7.2.4.2. Verwendung von Sonderzeichen . . . . . . . . . . . . . . . 7.2.5. Das Wichtigste in Kürze . . . . . . . . . . . . . . . . . . . . . . . . 7.2.6. Tipps für die Praxis . . . . . . . . . . . . . . . . . . . . . . . . . . Editieren von Texten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.3.1. Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.3.2. Aufrufen des kate Editors . . . . . . . . . . . . . . . . . . . . . . . 7.3.2.1. Sitzungen: . . . . . . . . . . . . . . . . . . . . . . . . . . 7.3.2.2. Erstellen einer neuen Datei . . . . . . . . . . . . . . . . . 7.3.2.3. Die Fenster des kate Editors . . . . . . . . . . . . . . . . 7.3.3. Wichtige Menüeinträge . . . . . . . . . . . . . . . . . . . . . . . . 7.3.4. Spezielle Kommandos zum praktischen Gebrauch . . . . . . . . . . 7.3.5. Andere Editoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwaltung von Dateien Teil 2 . . . . . . . . . . . . . . . . . . . . . . . . 7.4.1. Die einzelnen Merkmale einer Datei . . . . . . . . . . . . . . . . . 7.4.1.1. Die Dateimerkmale im Überblick . . . . . . . . . . . . . . 7.4.2. Gruppen und Owner . . . . . . . . . . . . . . . . . . . . . . . . . . 7.4.2.1. Zugriffsrechte unter Linux . . . . . . . . . . . . . . . . . . 7.4.3. Die Bedeutung von Devicegrenzen . . . . . . . . . . . . . . . . . . 7.4.3.1. Plattenplatzbelegung . . . . . . . . . . . . . . . . . . . . 7.4.3.2. Der Symbolic Link . . . . . . . . . . . . . . . . . . . . . . 7.4.4. Das Wichtigste in Kürze . . . . . . . . . . . . . . . . . . . . . . . . UNIX-Befehle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.5.1. Hilfe (Befehlsoptionen, Parameter, generelle Verwendungsweise, Verwendungsbeispiele) . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.5.2. Einsatz der UNIX-Shell: Pipes, >, < (Ausgabeumleitung) . . . . . 7.5.3. Kommandooptionen . . . . . . . . . . . . . . . . . . . . . . . . . . 7.5.4. Shells: bash, tcsh . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.5.5. Was ist los auf dem Rechner? . . . . . . . . . . . . . . . . . . . . . 7.5.6. Wegwerfen der Ausgabe einer Datei . . . . . . . . . . . . . . . . . 7.5.7. Archive anlegen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.5.8. Komprimieren von Dateien . . . . . . . . . . . . . . . . . . . . . . 7.5.9. Archivieren mit Komprimieren . . . . . . . . . . . . . . . . . . . . 7.5.10. Finden von Dateien und ausführen eines Befehls . . . . . . . . . . 7.5.11. Finden von Unterschieden in Dateien . . . . . . . . . . . . . . . . . 7.5.12. UNIX: Tokenisierung, Sortieren, Frequenzlisten . . . . . . . . . . . 7.5.13. Translate von Zeichen . . . . . . . . . . . . . . . . . . . . . . . . . 7.5.14. Sortieren-einer-wortliste . . . . . . . . . . . . . . . . . . . . . . . . 7.5.15. Report und Unterdrücken von Zeilen . . . . . . . . . . . . . . . . . 7.5.16. Erzeugen einer Wortliste . . . . . . . . . . . . . . . . . . . . . . . . Automatisieren von Befehlsfolgen mit der Shell . . . . . . . . . . . . . . . 7.6.1. Was ist ein Shellscript . . . . . . . . . . . . . . . . . . . . . . . . . 7.6.2. Benutzung von Shellscripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 100 101 101 101 102 102 103 103 103 104 104 105 105 105 106 107 107 108 109 110 110 111 111 111 111 112 114 114 114 114 115 . . . . . . . . . . . . . . . . . . . 115 116 116 116 116 117 117 117 117 117 118 118 118 118 119 119 120 120 120 Inhaltsverzeichnis 7.6.3. Das Wichtigste in Kürze . . . . . . . . . . . . . . . . 7.7. Drucken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.7.1. CUPS . . . . . . . . . . . . . . . . . . . . . . . . . . 7.7.1.1. Druckaufträge erzeugen (klassisch) . . . . . 7.7.1.2. Das Anzeigen von Druckjobs . . . . . . . . 7.7.1.3. Das Löschen von Druckjobs . . . . . . . . . 7.7.1.4. Das Wichtigste in Kürze . . . . . . . . . . 7.8. Linux-Befehle – eine kurze Übersicht . . . . . . . . . . . . . 7.8.1. Dokumentation, Dateien, Pfade . . . . . . . . . . . . 7.8.2. Textverarbeitung . . . . . . . . . . . . . . . . . . . . 7.8.3. Komprimieren von Dateien/ Ordnern . . . . . . . . 7.8.4. Dateisystem . . . . . . . . . . . . . . . . . . . . . . . 7.8.5. Prozessmanagement und User . . . . . . . . . . . . . 7.8.6. Zeichensätze . . . . . . . . . . . . . . . . . . . . . . 7.8.7. Umgebungsvariablen . . . . . . . . . . . . . . . . . . 7.8.8. Netzwerkeigenschaften . . . . . . . . . . . . . . . . . 7.8.9. Via Internet Dateien kopieren/ Rechner fernsteuern 7.8.10. Operatoren zur Ausgabe-/Eingabeumleitung . . . . 7.8.11. Versionsverwaltung . . . . . . . . . . . . . . . . . . . 7.8.12. Sonstiges . . . . . . . . . . . . . . . . . . . . . . . . v . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 121 121 121 121 121 121 122 122 123 124 124 125 126 126 126 127 127 127 128 Literaturverzeichnis 129 Abbildungsverzeichnis 130 Tabellenverzeichnis 131 A. Anhang 132 A.1. Die Backus-Naur-Form (BNF) . . . . . . . . . . . . . . . . . . . . . . . . . . 132 1. Geschichte und Aufgaben der Informatik Der Name Informatik besteht aus zwei Teilen: • Information • Mathematik siehe im Buch von Herbert Klären (Kla90) Die Informatik beschäftigt sich mit • Informationssystemen: Struktur, Wirkungsweisen, Fähigkeiten und Konstruktionsprinzipien • Modellen und Simulation • Möglichkeiten der Strukturierung, Formalisierung und Mathematisierung von Anwendungsgebieten Um für diese Bereiche Computerprogramme anbieten zu können, erforscht die Informatik: • abstrakte Zeichen, Objekte und Begriffe • formale Strukturen und ihre Transformation nach formalen Regeln • die effektive Darstellung solcher Strukturen im Rechner und der automatischen Durchführung der Transformationen. Anwendungen der Informatik finden wir unter anderem in folgenden Bereichen: • Handel • Industrie • Wissenschaft • Ingenieurwesen • Sozialwissenschaft • Medizin • Ausbildung • Kunst • Freizeit Eine sehr gute Einführung in die Informatik findet sich im Buch (H.-94) 1 2 1. Geschichte und Aufgaben der Informatik 1.1. Rechner der nullten Generation • 1623 – 1624: Wilhelm Schickard Ein Universalgenie konstruiert die wohl erste Rechenmaschine. Auf sein Konto geht das Konstruktionsprinzip von Ziffernrädern und Zehnerübertragung. • 1642: Blaise PASCAL führt in Paris eine Maschine vor, die addieren und auf Umwegen auch subtrahieren kann. Sie hatte zehnstufige Zahnräder, der Zehnerübertrag wurde durch eine Klaue und Mitnehmerstifte realisiert. • 1673: Gottfried Leibnitz stellt in London seine Replica vor, die alle 4 Grundrechenarten mit 12-stelliger Anzeige bewältigen kann. Er erfindet außerdem das Dualsystem. • 1822: Charles Babbage Er entwickelt das Konzept der difference engines zur Überprüfung von Logarithmentafeln. Doch war es damals nicht möglich, ein mechanisches Getriebe zu bauen, bei dem 25 Zahnräder ineinandergreifen können, ohne zu verklemmen. 1833 entwarf er das Konzept der analytical engine, der ersten digitalen Rechenanlage. Sie enthielt schon sämtliche Komponenten einer modernen Rechenanlage: – arithmetischer Zahlenspeicher – arithmetische Recheneinheit – Steuereinheit zur Steuerung des Programmablaufs einschließlich der Rechenoperationen und des Datentransports – Geräte für Ein-/Ausgabe – dekadische Zahnräder für die Rechnung – zur Steuerung: Lochkarten – logische Verzweigungen und Entscheidungen – Die Addition sollte 1 sek., die Multiplikation zweier 50-stelliger Zahlen 1 Minute dauern. Zu Lebzeiten bezeichnete man ihn als Narren und keiner verstand ihn. Seine Frau Augusta Ada veröffentlichte seine Arbeiten und sein Sohn versuchte Teile dieser Maschine zu bauen, die heute noch im Science-Museum zu London zu besichtigen sind. • 1847: George Boole Er entwickelt einen Formalismus für die mathematische Behandlung von verschiedenen Aussageverknüpfungen, die mit den beiden Begriffen „wahr“ und „falsch“ arbeiten. Heute spricht man von der Bool´schen Algebra. • 1938: Konrad Zuse entwickelt ein Rechnerkonzept mit den logischen Grundoperationen. Er schlug einen programmgesteuerten Rechenautomaten mit 1500 Elektronenröhren vor. Die deutsche Regierung beurteilte eine solche Entwicklung als völlig sinnlos. Im Auftrag der deutschen Luftfahrtindustrie entsteht 1941 die Z3, ein Rechner mit 600 Relais im Rechenwerk und 2000 Relais im Speicherwerk. In den USA wurde parallel dazu 1944 völlig unabhängig von Prof. H. Aiken, Professor für angewandte Mathematik an der Harvard University den Rechner MARK 1 entwickelt. Er bestand aus: – 17 Gestellen mit Motoren und Drehschaltern 1.2. Rechner der ersten Generation 1946 – 1965 3 – 3000 Kugellagern – 800 km Leitungsdraht – 760.000 Einzelteilen Eine Multiplikation benötigte 6 Sekunden (sie wurde in der NAVY für die Errechnung von Funktionstabellen verwendet). • 1945: John v. Neumann entwickelt in einer genialen Abstraktion des Steuerungsprozesses folgendes Programmierschema: Das steuernde Programm wird als Information codiert und in den Informationsspeicher des Rechners mit eingelagert. – Programmsprünge innerhalb des Programms möglich – Steigerung der Rechengeschwindigkeit Erst 1949 wurde dieses Konzept zum ersten Mal angewendet. Beispiel: Strickmaschine Fest eingestelltes Programm: Start → Ergebnis (keine Sprünge) Bei Neumann: Programm + Daten, Programm wird codiert → Sprünge sind erforderlich. Arbeitsweise der Rechner der 0. Generation Anweisungen, also Programme von außen mittels Lochkarten, Lochstreifen oder Programmstecktafeln. Programmverzweigungen, Schleifen und Unterprogramme nur mit Spezialeinrichtungen wie zusätzlichen Programmstreifenleser und Endlosschleifen möglich. 1.2. Rechner der ersten Generation 1946 – 1965 • 1946: wurde an der Universität von Pennsylvania der erste Röhrenrechner entwickelt →ENIAC Electronic Numerical Integrator And Computer. – 18.000 Röhren – 1500 Relais – 70.000 Widerstände – 10.000 Kondensatoren – mehr als eine halbe Million Lötstellen – 30 Tonnen Gewicht – Addition 0.2 · 10−3 Sekunden – Multiplikation 2.8 · 10−3 Sekunden. – Leistungsverbrauch 150 KW – Rechensystem dezimal. Wurde für die Lösung von Differentialgleichungen am Ballistic Research Labor eingesetzt. Der Rechner war sehr zuverlässig, da die Röhren nur mit 25% ihrer Leistungsfähigkeit betrieben wurden. Die Ausfallrate betrug 2 - 3 Röhren pro Woche. • 1951: wurde das UNIVAC (Universal-Automatic Computer)-System entwickelt: – Röhrenrechner – gemischtes Dual-Dezimal-System 4 1. Geschichte und Aufgaben der Informatik – Addition 120 ms – Multiplikation 1.8 ms – Division 3.6 ms Von der UNIVAC wurden insgesamt 45 Systeme hergestellt. Der Rechner bestand aus: – 5000 Röhren – 18.000 Dioden – 300 Relais – Als Speicher wurden Quecksilber-Verzögerungsleitungen (höchst giftig) verwendet. • 1952: entwickelt IBM einen legendären Rechner mit der Bezeichnung 701 Die Leistungsmerkmale sind: – sehr schnell, ebenfalls Röhrenrechner – als Hintergrundspeicher: Magnetband aus Kunststoff (bisher Metall-Magnetband). • 1957: Entwicklung der Programiersprache FORTRAN (Formula Translation) Das Einsatzgebiet der Programmiersprache war im Numerischen Bereich der Mathematik. Der Leiter der Forschungsgruppe, die FORTRAN entwickelte, war John Backus. Anlagenstruktur der Rechner der ersten Generation: Die Rechner arbeiten im Blockzeitbetrieb. Das Programm arbeitet mit einem Operator zusammen, der Schalter umlegen muss. Dadurch arbeitet das Programm direkt mit der Befehlsschnittstelle. E/A-Geräte werden ebenfalls vom Rechner bedient. Dadurch sehr langsamer Durchsatz. 1.3. Die Rechner der zweiten Generation 1957 – 1963 In dieser Rechnergeneration wurde folgendes entwickelt bzw. eingesetzt: - Entwicklung der Transistortechnik - Rechner arbeiten mit Binärsystem - Magnetspeicher • 1956: IBM führt den Rechner 305 ein (CDC 66000). • 1956: Entwicklung der IC-Technik (integrated circuit) bei Texas Instruments Bei einem IC wird auf photomechanischem Weg in einem kleinen Halbleiterstück die elekronische Wirkung von Transistoren, elektrischen Widerständen und Kondensatoren erreicht. Die Anzahl der simulierten Bausteine resultiert aus der sogenannten Packungsdichte der Transistoren. • 1958: Entwicklung der Programmiersprache LISP von John McCarthy • 1959: Die Programmiersprache COBOL (Common Business Oriented Language) wird entwickelt. 1.4. Rechner der dritten Generation 1964 – 1981 5 • 1960: In Europa wird die erste blockstrukturierte Programmiersprache ALGOL 60 (Algorithmic Language) von führenden Wissenschaftlern der Welt auf mehreren Tagungen entwickelt! (unter Beteiligung von Prof. Bauer, TU München) Anlagenstruktur der Rechner der zweiten Generation: - Stapelbetrieb mit Vorrechnern - Programme werden als Stapel eingegeben - Langsame Peripherie auf Vorrechner - Compiler, Bibliothek auf MB (Operator muss nur noch Schalter auf MB umlegen) 1.4. Rechner der dritten Generation 1964 – 1981 In dieser Rechnergeneration wurde folgendes entwickelt bzw. eingesetzt: • IC-Technik • Microprozessoren, 8 und 16 Bit • Schnelle Speicher Microprozessoren erweitern die bisherige Funktionalität eines ICs um folgende Komponenten, die auf photomechanischem Weg in einen Halbleiterbaustein eingebrannt werden. Microprozessoren bestehen aus folgenden Komponenten: • Steuerwerk • Rechenwerk • Befehlszeilen • Akkumulator • Befehlsregister • Register Die einzelnen Komponenten konnten Binärzahlen verarbeiten. Die Wortlänge der Binärzahlen war in den ersten Microprozessoren 4 Bit. • 1962: Weiterentwicklung von FORTRAN zu FORTRAN IV • 1965: erster Prozessorrechner von DEC PDP8: Minicomputer, kostete weniger als 20.000$. Die Anzahl der Transistoren pro Chip nahm zu. • 1968: Es entsteht ALGOL 68 und eine ANSI Spezifikation von COBOL Common Business Oriented Language. COBOL wird in der Betriebswirtschaft und dem Bankwesen eingesetzt, da COBOL sehr gute kaufmännische Routinen zur Verfügung stellt. • 1970: Erfindung des Mikroprozessors von Intel 1103 (4bit) Es beginnt die Arbeit an PROLOG = programming in logic. Weiterentwicklung von LISP. PASCAL wird von Niklaus Wirth erfunden 6 1. Geschichte und Aufgaben der Informatik • 1971: Der erste General-Purpose Microprocessor wird von der Firma Intel entwickelt: Intel 4004, 4 Bit, 108 kHz Taktung, Geschwindigkeit: 0,06 MIPS, enthält 2300 Transistoren. Der Chip wurde im Auftrag der japanischen Firma Busicom entwickelt und von der Firma Intel für $60000 zurückgekauft. • 1972: Epoche der Großintegration LSI: Large Scale Integration (mehrere tausend Transistoren auf einem Chip), Dennis Ritchie entwickelt die Programmiersprache C • 1974: Intel entwickelt den ersten 8 Bit Chip, den 8080. Er wurde als erster CHIP weitverbreitet in Ampelsteuerungen eingesetzt. • 1975: Tiny BASIC wird definiert und auf einem Microcomputer mit 2 KB RAM von Bill Gates und Paul Allen zum Einsatz gebracht. Die Entwicklung von Kleinrechnern beginnt, als komplette Leiterplatinen entwickelt wurden auf denen - ICs - Mikroprozessoren - Datenspeicher aufgelötet waren. Durch die Erweiterung der Platinen um Peripherie, Stromversorgung, Terminal, Keyboard und Gehäuse konnte man nun Kleincomputer selbst zusammenstellen. • 1976: Der 24-jährige Steve Jobs und der 20-jährige Steve Wosniak gründen ein Unternehmen und bauen um den Microprozessor 6502 den ersten Kleinrechner. Sie vervollständigen die Kits um Peripherie (Tastatur, Bildschirm) und schreiben zugehörige Software. Sie nennen die Firma „Apple“. Die Packungsdichte der Transistoren vergrößert sich: • 1977: 16K-Speicher werden entwickelt. Die Chips haben 20.000 Transistoren auf einem Baustein. • 1978: Der zweite 8-bit-Microprozessor INTEL 8086, der Start der erfolgreichen x86 Architektur, wird entwickelt. Einführung des ZILOG Z80 mit dem berühmten Betriebssystem CP/M Erste optische Datenspeicher werden vorgestellt (Phillips) • 1979: Höchstintegration auf Chips (VLSI: Very Large Scale Integration, d.h. mehr als 100.000 Transistoren auf einer Fläche von 20 x 40 mm2 ) - neue Transistormaterialien: Galliumarsenid - schnelle Schalter: Josephson Schalter mit einer Schaltzeit von 13 · 10−12 sec., allerdings nur bei einer Temperatur von -269°C - große Speicherbausteine - 2-Mbit-Speicher (Bubble-Speicher). Als schnelle Hintergrundspeicher werden Plattenlaufwerke entwickelt. Programmiersprachen: PASCAL, LISP Anlagenstruktur der Rechner der dritten Generation: Kleinrechner und Timesharingsysteme mit Bildschirm und Tastatur. 1.5. Die Rechner der vierten Generation 1982-1989 7 1.5. Die Rechner der vierten Generation 1982-1989 In dieser Rechnergeneration wurde folgendes entwickelt bzw. eingesetzt: - 32-bit-Mikroprozessoren (160.000 Transistoren) - 128k große Speicher auf einem Chip. - Computer werden über Netzwerke verbunden. Damit beginnt das Zeitalter des Distributed Processing. • 1983: Die Programmiersprache Smalltalk-80 wird implementiert. Die Programmiersprache ADA entsteht im Auftrag des DoD. ADA war der Versuch des Amerikanischen Verteidigungsministerium, eine Programmiersprache einzuführen, die als Standard für alle militärischen Entwicklungen verwendet werden sollte. Ein Microprocessor mit sehr guten I/O Möglichkeiten, der MOTOROLA 68000, wird entwickelt. Mit diesem Processor können die Graphische Oberflächen leicht programmiert werden. Er wird zum ersten Mal im Rechner APPLE LISA von Steve Woszniak und Steve Jobs eingesetzt. • 1985: INTEL entwickelt den 80386 Processor • 1986: Es entstehen TURBO PASCAL, Eiffel. C++ wurde von Bjarne Stroustrup entwickelt und war eine Weiterentwicklung von „C“, d.h. Abwärtskompatibilität zu C war vorhanden. Dazu kam das objektorientierte Konzept (programmierabhängige Definition von Objekten) Die Firma MIPS entwickelt den ersten RISC Prozessor R2000 • 1985: Die Firma SUN entwickelt ihre RISC SPARC Architektur. • 1988: Es entsteht COMMON LISP und von Nikolaus Wirth das System OBERON, ein Nachfolger von MODULA-2 • 1990: C++ wird überarbeitet und es entsteht C++ Version 2.0 • 1991: Visual BASIC entsteht. • 1995: Die Programmiersprache ADA wird überarbeitet und von einem ANSI Komitee standardisiert zu ADA95 1.6. Die Rechner der fünften Generation In dieser Rechnergeneration wurde folgendes entwickelt bzw. eingesetzt: - größere Packungsdichte auf den Chips und dadurch größere und schnellere Speicher. - Man spricht von 1 Million Transistoren auf einem Chip - widearea Netzwerke - künstliche Intelligenz und Expertensysteme - VHLSI (very high large scale integration) - 3D-Prozessoren - selbstlernende Systeme (Artificial Intelligence) 8 1. Geschichte und Aufgaben der Informatik - Software in Silicon - natürliche sprachliche Systeme Diese Rechnergeneration ist mit großen Ankündigungen gestartet und hat vieles, was sie erreichen wollte, nicht erlangt. Speziell in Japan wurden Milliardenbeträge in die Entwicklung von Systemen mit künstlicher Intelligenz gesteckt, die nicht zu dem erwarteten Ziel geführt haben. Folgende Vorhaben wurden nicht erreicht: „Der Computer, der denkt wie der Mensch“, „Spracherkennung fließender Rede“, „Automatische Übersetzung“, „BIOChips“, „Microprozessoren mit Lichtwellenleitern“ Dagegen haben sich in anderen Gebieten umwerfende Entwicklungen ereignet: −→ Neue Mikroprozessortechnologie: - RISC Hardware statt CISC - General Purpose CPU’s - Pipelineing und Parallelrechner −→ Weltweite Vernetzung von Rechnern - Internet −→ Multimediasysteme auf dem PC 1.7. Die Rechnergenerationen bis ca. 1990 im Überblick Tabelle 1.1 auf Seite 9 fasst die Rechnergenerationen bis ca. 1990 im Überblick zusammen. Gespeicherte Programme, Lochkarten 2 Kbyte Speicher, 10KIPS Schnelligkeit erste 1946 – 65 ENIAC, UNIVAC, IBM 701 Röhrenrechner, Dezimalsystem Software Eigenheiten Generation Jahr Rechner 2 Mbyte Speicher, 5 MIPS dritte 1964 – 81 IBM 360, PdP 11, CYBER 205 IC-Technik, Microprozessoren (4,8,16 BIT), LSI, Minicomputer, Magnetplatten PASCAL, LIPS, Computergraphik, Timesharing C, UNIX, ADA, PROLOG, Objektorientierte Sprachen (C++), Datenbanken 8 Mbyte Speicher, 30 MIPS vierte 1982 – 89 CRAY XMP, SPERRY 1100/90, Sparc (SUN) Multiprocessoren, (32 BIT) VLSI, Microcomputer, Optische Platten Tabelle 1.1.: Die Rechnergenerationen bis ca. 1990 im Überblick 32 Kbyte Speicher, 2000 KIPS FORTRAN, ALGOL, COBOL Transistortechnik, Binärsystem zweite 1957 – 63 CDC 6600, IBM 306 1 Gbyte Speicher, Giga Flops Multimediale Betriebssysteme, Expertensysteme RISC, Mulitprocessoren (64 BIT), Optische und neuronale Bausteine fünfte ab 1989 CRAY T3D 1.7. Die Rechnergenerationen bis ca. 1990 im Überblick 9 10 1. Geschichte und Aufgaben der Informatik 1.8. Verwendete Abkürzungen IC – Integrated Circuit (= Transistor) LIS – Large Scale Integration: mehr als 1000 Transistoren auf einem Baustein VLSI – Very Large Scale Integration: mehr als 100000 Transistoren auf einem Baustein Byte – 8 Bit, wird benötigt, um einem Buchstaben zu speichern. Kbyte – 1000 Byte, Mbyte – 100000 Byte, 1000 Kbyte, Gbyte – 10 hoch 9 Byte, 1000 Mbyte IPS – Instructions per Second, MIPS – 1 Million Instruktionen pro Sekunde Flops – „Floating Point“-Operationen pro Sekunde 2. Die Programmiersprache Perl 2.1. Allgemeines zu Perl Die Progammiersprache Perl wurde von Larry Wall erfunden und in seinem Buch Programming Perl 1991 (LW00) veröffentlicht. Der Name perl ist die Abkürzung für „Practical Extraction and Report Language“. Perl gibt es momentan in der Version 5.x und wird über eine zentrale Homepage verwaltet. Die Version 6 ist schon seit einiger Zeit mit vielen, nahezu ’revolutionären’ Neuigkeiten angekündigt, aber noch in der Entwicklung. http://language.perl.com In dieser Homepage finden sich Verweise zu aktuellen Softwarepaketen, Modulen und Dokumentationen. Larry Wall schreibt folgendes zu Perl: (aus http://language.perl.com/info/synopsis.html, Adresse Stand: Nov 97) Perl is an interpreted language optimized for scanning arbitrary text files, extracting information from those text files, and printing reports based on that information. It’s also a good language for many system management tasks. The language is intended to be practical (easy to use, efficient, complete) rather than beautiful (tiny, elegant, minimal). It combines (in the author’s opinion, anyway) some of the best features of C, sed, awk, and sh, so people familiar with those languages should have little difficulty with it. (Language historians will also note some vestiges of csh, Pascal, and even BASIC-PLUS.) Expression syntax corresponds quite closely to C Expression syntax. Unlike most Unix utilities, Perl does not arbitrarily limit the size of your data–if you’ve got the memory, Perl can slurp in your whole file as a single String. Recursion is of unlimited depth. And the hash tables used by associative arrays grow as necessary to prevent degraded performance. Perl uses sophisticated pattern matching techniques to scan large amounts of data very quickly. Although optimized for scanning text, Perl can also deal with binary data, and can make dbm files look like associative arrays (where dbm is available). Setuid Perl scripts are safer than C programs through a dataflow tracing mechanism which prevents many stupid security holes. If you have a problem that would ordinarily use sed or awk or sh, but it exceeds their capabilities or must run a little faster, and you don’t want to write the silly thing in C, then Perl may be for you. There are also translators to turn your sed and awk scripts into Perl scripts. 2.2. Kurzübersicht zu Perl Ziel der Programmiersprache war es, einfache Programmierprobleme einfach ausdrücken zu können. Es sollten keine Variablen deklariert, keine Typen festgelegt werden. Der Umgang mit Dateien sollte so einfach wie möglich sein. Stringvergleiche sollten über mächtige reguläre Ausdrücke realisiert werden können. Die Programmiersprache Perl wurde stark vom Betriebssystem UNIX und der Programmiersprache C beeinflusst und wurde zu Beginn hauptsächlich zur Abarbeitung von Texten und Aufrufen von Diensten für 11 12 2. Die Programmiersprache Perl das Betriebssystem eingesetzt. Nach und nach wurden weitere Programmbibliotheken für Perl entwickelt, die es ermöglichen, Perl in nahezu allen Bereichen der Arbeit mit dem Betriebssystem einzusetzen. Die großen Möglichkeiten, die Perl für die Bearbeitung von Texten bereitstellt, haben auch dazu geführt, dass Perl in der Textbearbeitung mehr und mehr eingesetzt wird. Die Entwickler sagen zwar, dass es sehr leicht ist, Perl-Programme zu schreiben, vergessen aber, dass dies nur für Programmierer zutrifft, die Namens- und Zeichenkonventionen von UNIX und C beherrschen und außerdem in der Lage sind, mit regulären Ausdrücken umzugehen. Die vorherige Kurzbeschreibung von Perl wurde hauptsächlich aus dem Buch „Programming Perl“ (LW00) entnommen. Perl ist eine interpretierende Programmiersprache. Programme werden also nicht kompiliert und gelinkt, sondern es wird der Sourcecode vom Programm perl direkt interpretiert. Eine sehr gut Einführung in das Programmieren mit PERL findet sich im Buch von Randal L. Schwarz (TP01) 2.3. Aufbau eines Perl Programms 2.3.1. Das erste Perl-Programm #!/ usr / bin / perl # Erstes Perl Programm use strict ; { print (" Hallo wie geht ' s \ n "); } Formatierungskonvention: • Die Variablendeklaration und die Anweisungen des Hauptprogramms werden 24 Zeichen eingerückt, die Einrücktiefe wird im gesamten Programm bei Blöcken beibehalten. Zur Einrückung keine Tabstops verwenden! Die meisten grafischen Editoren unterstützen das Feature: Obwohl sie bei diesen Editoren die Tabulatortaste drücken, werden in der Datei Leerzeichen eingefügt. • Alle Anweisungen stehen untereinander 2.4. Start eines Perl Programms 13 • pro Zeile nur eine Anweisung Aus historischen Gründen steht hier das erste C-Programm, das in der ersten Vorlesung „Einführung zur Programmierung“ im Jahre 1992 angegeben wurde: /* */ Filename : hallo . c Schreibt Text auf den Bildschirm # include < stdio .h > main () { puts (" Hallo , hier ist der Sepp ."); } 2.4. Start eines Perl Programms Perl Programme sind keine Maschinenprogramme, sondern Textdateien, die von Perl interpretiert werden. Nachdem das Perl Programm in einer Datei abgespeichert wurde, kann es mit dem Befehl perl datei gestartet werden. Damit der Befehl perl datei auf einem Rechner funktioniert, müssen aber einige Bedingungen erfüllt sein: • Das Programm perl wurde auf dem Rechner installiert. • Das Programm perl muss in einem Verzeichnis installiert sein, das Aufgrund des Inhalts der PATH Umgebungsvariable durchsucht wird. (Im allgemeinen /usr/bin, oder /usr/local/bin) Werden die Zugriffsrechte der Datei unter UNIX auf ausführbar (executable) gesetzt, kann man das Programm selbst als Befehl aufrufen, wenn die erste Zeile des Perl Programms eine sogenannte ident - Line enthält in der Perl als Befehl steht. (Im Allgemeinen: #!/usr/bin/perl) 2.5. Editieren und Starten eines Perl - Programms mit dem UNIX Programm kate In der folgenden Abbildung 2.1 wird ein Screenshot des KATE Editors unter LINUX gezeigt. Hier ist zu sehen, wie eine PERL Datei mit Hilfe von Kate bearbeitet werden kann. Eine genauere Beschreibung des KATE Editors finden sie im Kapitel LINUX 7.1 und dort im Abschnitt 7.3.2, „Aufrufen des kate Editors“ auf Seite 106. 14 2. Die Programmiersprache Perl Abbildung 2.1.: Editor:Kate 2.5.1. Bemerkungen zur Syntax von Perl Programmen Perl Programme haben ein freies Format, das heißt, dass Leerzeichen zwischen den Variablen oder Programmzeilen keine Rolle spielen. Theoretisch könnte ein Perl Programm auf einer Zeile stehen. Es wird aber empfohlen, dass zur besseren Lesbarkeit Leerzeichen eingestreut werden. Zur Formatierung empfiehlt es sich keine Tabulatoren zu verwenden, da die Position der Tabulatoren auf unterschiedlichen Systemen verschieden sein können. Außerdem verbieten Programmiersprachen wie Python den Einsatz von Tabulatoren als Formatierungselement. • Jedes Perl Statement endet mit einem Semikolon. • Das Zeichen # definiert den nachfolgenden Text bis zum Zeilenende als Kommentar und ist für das Perl Programm irrelevant. 2.6. Datenstrukturen 1: Skalare und Listen 15 2.6. Datenstrukturen 1: Skalare und Listen 2.6.1. Vorbemerkung Die Elemente eines Programms sollen das zu programmierende Sachgebiet so realistisch wie möglich wiederspiegeln. Deshalb wählt der Programmierer dementsprechend die • Datenstrukturen • Operationen aus einer Programmiersprache, die der Realität am nächsten kommen. Die Datenstrukturen bestimmen die Menge von Konstanten und Variablen, die in einem Programm verwendet werden können. Die wichtigsten Operationen innerhalb von Datenstrukturen sind: • Zuweisung • Vergleich 2.6.2. Einfache Datenstrukturen: Skalare Die einfachen Datenstrukturen sind die Standardtypen einer Programmiersprache. Für sie sind Operatoren und Operationen definiert. Die Struktur im Speicher ist eindeutig festgelegt und kann vom Programmierer nicht verändert werden. In Perl werden die einfachen Standardtypen Skalare genannt. Diese umfassen Numerische Typen und Buchstabenketten. Buchstabenketten heißen auch Strings. In Perl gibt es folgende numerische Standard-Typen numerical literals • ganze Zahlen – Operationen: +, - *, /, % – Beispiel:1, 2, -123, Hexadezimalzahl: 0xaff, Oktalzahl : 0372 • reelle Zahlen – Operationen: +, - *, / – Beispiel: 1.2, -3E4, -0.06 In Perl gibt es folgenden String Standard-Typen string literals • strings – Die Buchstabenkette muss bei Perl in Double Quotes eingeschlossen werden – Operationen: . und x – Beispiel: “abcde”, “a” 2.6.3. Zusammengesetzte Datenstrukturen: Listen Bei zusammengesetzten Datenstrukturen werden beliebige Datenstrukturen zu einem Datentyp zusammengefasst. Die einfachste zusammengesetzte Datenstruktur ist die Strukturart Liste. Listen werden auch Felder (Arrays) genannt. In Perl werden Listen dadurch kreiert, dass Skalare, mit Komma getrennt, hintereinander aufgelistet und mit runden Klammern umschlossen werden: (Element1 , Element2 , . . . ,Elementn ) 16 2. Die Programmiersprache Perl Die Reihenfolge der Auflistung definiert die Position der einzelnen Elemente innerhalb der Liste. Außerdem wird ihnen eine Positionsnummer, bzw. ein Index zugeordnet. Das erste Element bekommt die Positionsnummer (=Index) 0 das zweite die Nummer 1, das n-te Element die Positionsnummer n-1. Beispiel 2.1 ("Moni", "Sepp", "Franz", "Müller") Elementnummer erstes Element zweites Element drittes Element viertes Element Index 0 1 2 3 Wert “Moni” “Sepp” “Franz” “Müller” Tabelle 2.1.: Elemente in einer Liste Das besondere Merkmal von Listen ist, dass die einzelnen Elemente über die Positionsnummer, den sogenannten Index angesprochen werden können. 2.7. Variablen Um in einer Programmiersprache mit Daten zu arbeiten, muss man Variablen für den entsprechenden Datentyp deklarieren. Der Name der Variablen ist dann ein Synonym für den Speicherbereich, unter dem der Wert abgespeichert wird. Unter dem Variablennamen können auf eindeutige Art Werte in diesen Bereich abgelegt und herausgelesen werden. Als Variablennamen kann man beliebige Zeichenketten aus Buchstaben und Zahlen verwenden, wobei der Name mit einem Buchstaben beginnen muss und kein Leerzeichen enthalten darf. In Perl werden Groß- und Kleinbuchstaben in Variablennamen unterschieden. Beispiel 2.2: Variablennamen zulässige Variablennamen : wert x1 X1 unterscheidet sich vom kleingeschriebenen x1 unzulässige Variablennamen : 1wert beginnt mit einer Zahl as enthält ein Leerzeichen In Perl muss bei jeder Variablen festgelegt werden, wie der Wert der Variablen interpretiert werden soll. Die Art der Interpretation wird von speziellen Zeichen am Anfang der Variablen definiert. • Zugriff auf den Wert einer Variablen als Skalar: Der Variablenname beginnt mit einem Dollar ($). Die Variable wird den Wert als Skalar speichern, bzw. zurückgeben: z . B . $wert • Zugriff auf den Wert einer Variablen als Liste: Der Variablenname beginnt mit einem at (@). Die Variable soll den Wert einer Liste speichern, bzw. zurückgeben: z . B . @namen 2.7. Variablen 17 2.7.1. Deklaration Die Programmiersprache Perl schreibt nicht vor, dass eine Variable vor ihrem Gebrauch deklariert werden muss. Für die Übersichtlichkeit, zur Vermeidung von Tippfehlern und um einen guten Programmierstil zu gewährleisten, sollte man die Variablen aber trotzdem deklarieren. Schreibt man folgende use-Zeile: use strict; schaltet Perl zahlreiche syntaktische Überprüfungen ein, es akzeptiert dann z.B. nur zuvor deklarierte Variablen. Wenn nur die syntaktische Überprüfung eingeschaltet werden soll, kann man die use strict Anweisung mit einem Zusatz 'vars' einschränken: use strict 'vars'; Mit dieser Anweisung überprüft der Perl-Interpreter beim Aufruf der Perldatei, ob alle Variablen richtig deklariert wurden. Damit kann der Programmierer Tippfehler oder doppelte Deklarationen einer Variablen vermeiden. Formatierungskonvention: • Verwenden Sie sprechende Variablennamen! $x = " Helsinki " ist zwar schön kurz, aber spätestens zehn Zeilen später weiß niemand mehr, was diese Variable beinhaltet. $stadt , $ort oder irgendwas Vergleichbares wären je nach Kontext sehr viel besser. • Vermeiden Sie zu lange Variablennamen. Beispiel 2.3 Skalare: my $zahl ; my $farbe ; Listen: my @namen ; my @werte ; Beispiel 2.4: Arbeiten mit Skalaren und Arrays #!/ usr / bin / perl # file :/ DieSprache / glueckszahlen . perl # Demonstration von if - else - Anweisung use strict ; { my @glueckszahlen ; my $zahl ; @glueckszahlen = ( 13 , 12 , 27 ); print (" Geben Sie eine Zahl ein , ich sage , ob es eine Glückszahl ist :\ n "); $zahl = < >; if ( $glueckszahlen [0] == $zahl ) { print (" Die eingegebene Zahl ist identisch zur ersten Glückszahl \ n "); } 18 2. Die Programmiersprache Perl } elsif ( $glueckszahlen [1] == $zahl ) { print (" Die eingegebene Zahl ist identisch zur zweiten Glückszahl \ n "); } elsif ( $glueckszahlen [2] == $zahl ) { print (" Die eingegebene Zahl ist identisch zur dritten Glückszahl \ n "); } Exkurs: Bei der Programmiersprache Perl wird bei der ersten Verwendung einer Variablen der notwendige Datenbereich sofort alloziert. Diese Konvention führt bei großen Programmen schnell zu Programmierfehlern, da Tippfehler in Variablennamen nicht erkannt werden, sondern eine neue Variable mit dem vertippten Namen deklariert wird. Deshalb empfehlen wir, die verwendeten Variablen vor der Verwendung zu deklarieren. Beispiel 2.5: Beispiel für einen Programmkopf #!/ usr / bin / perl # Muster für einen Programmkopf use strict ; { my ( $zaehler ); # Deklaration $zaehler = 2; # Initialisierung ... } 2.8. Ausdrücke Mit Hilfe von Operatoren können Operanden verknüpft werden, um neue Werte zu berechnen. Die Verknüpfung von ein oder mehreren Operanden mit einem oder mehreren Operatoren bezeichnet man als Expression, oder auch Ausdruck. In Perl gibt es einfache numerische Ausdrücke, string Ausdrücke und relationale Ausdrücke. Numerische Ausdrücke kombinieren numerische Werte mit numerischen Operatoren, String Ausdrücke verknüpfen string Werte mit string Operatoren und relationale Ausdrücke werden mit relationalen Operatoren gebildet. In Ausdrücken können auch Variablen vorkommen, die dann gemäß der Operatoren und des Variablentyps ausgewertet werden und deren Wert in die Berechnung des Ausdrucks einfließt. Beispiel 2.6: Ausdrücke Arithmetische Ausdrücke: 2 + 2 / 2.3 2 * 3 5 - 4.2 $zahl String Ausdrücke: " max "." münchen " relationale Ausdrücke: 1 <= 3 2.8. Ausdrücke 19 2.8.1. Wertzuweisung Jeder Variablen kann ein Wert über Konstanten oder über einen Ausdruck seines Datentyps zugewiesen werden. Skalarvariablen können Skalare, bzw. Ausdrücke die einen Skalar als Ergebnis liefern, zugewiesen werden. Listenvariablen können Listen, bzw. Ausdrücke die eine Liste als Ergebnis liefern, zugeordnet werden. Skalare können intern numerische oder string Daten enthalten. Listen können sich intern sowohl aus numerischen, als auch aus string Elementen zusammensetzen. Der Typ des Wertes, der in einer Variable zum ersten Mal gespeichert wird, legt den internen Standardtyp der Variable fest. Bei Zuweisung einer Zahl wird der Variablen der interne Datentyp: Numerischer Standardtyp zugeordnet. Bei der Zuweisung eines Strings wird der Variable der interne Datentyp: String Standardtyp zugeordnet. 2.8.1.1. Zuweisung einer Konstanten Variablen wird bei der Initialisierung meistens eine Konstante zugewiesen. Die erste Wertzuweisung einer Variable legt den internen Standardtyp der Variable fest. Beispiel 2.7: Variableninitialisierung # Skalare Variable , Interner Standardtyp : Numerisch $x =5; # Skalare Variable , Interner Standardtyp : String $farbe = " rot "; # Listen Variable , Interne Standardtypen : String , String , String @namen = (" moni " ," gabi " ," martin "); # Listen Variable , Interne Standardtypen : # Numerisch , Numerisch , Numerisch , Numerisch , Numerisch @werte = (1 ,2 ,3 ,4 ,5); # Listen Variable , Interne Standardtypen : # String , String , Numerisch , Numerisch , Numerisch @eintrag = (" Katja " ," Putin " ,20 ,3 ,1974); 2.8.1.2. Zuweisung eines Ausdrucks Variablen kann auch der Wert eines Ausdrucks zugewiesen werden. Bei der Zuweisung darf sich aber der Wert des Ausdrucks nicht mit der Datenstruktur der Variablen (Skalar oder Liste) und dem internen Standardtyp (numerisch oder string) widersprechen. Formatierungskonvention: • Schreiben Sie nie mehrere Zuweisungen in einer Zeile • Wenn mehrere Zuweisungen in nachfolgenden Zeilen stehen, sollen die Zuweisungszeichen untereinander stehen. • Verwenden Sie zur Ausrichtung keine Tabulatoren, sondern Leerzeichen 20 2. Die Programmiersprache Perl Beispiel 2.8: arithmetischer Ausdruck my $erste_zahl = 2; my $zweite_zahl = 4; $erste_zahl = $erste_zahl * $zweite_zahl ; $erste_zahl = $erste_zahl + 1; Bei einer Wertzuweisung wird der Wert des Ausdrucks auf der rechten Seite des Gleichheitszeichens berechnet und der Variablen links vom Gleichheitszeichen zugewiesen. Die rechte Seite vom Gleichheitszeichen wird rvalue genannt, die linke Seite lvalue. rvalues müssen immer einen Wert ergeben. lvalues müssen immer eine Variable sein. Beispiel 2.9: Wertzuweisung, unzulässiges Beispiel 2 = $erste_zahl * $zweite_zahl ; # ( Zahl 2 als lvalue ist keine Variable ) In einem Ausdruck kann auch der Aufruf einer Subroutine vorkommen, deren Ergebnis dann weiterverwendet wird. Beispiel 2.10: Konvertieren eines Stringskalars in eine Buchstabenliste Konvertieren eines Stringskalars in eine Buchstabenliste und Ermittlung der Anzahl der Buchstaben in einem String. $name = " abcd "; @buchstaben = split (// , $name ); $string_laenge = length ( $name ); 2.8.2. Einlesen der Daten vom Terminal Zum Lesen von Daten von der Tastatur gibt es in Perl keine spezielle Leseroutine, das Lesen der Daten von der Tastatur wird wie das Lesen von einer Datei realisiert. Unter Perl und auch unter UNIX kann die Tastatur über den Filehandle STDIN angesprochen werden. Erklärung: Ein Filehandle ist der Name des Kanals (z.B. eine Datei), über den die Einoder Ausgabe erfolgt. Ihre Benennung unterliegt den gleichen Kriterien wie die Benennung von Variablen, sie bestehen aber aus Großbuchstaben und sind von spitzen Klammern (Diamantoperator) umschlossen. Es gibt 6 eingebaute, intern belegte Namen von Filehandles: STDIN, STDOUT, STDERR, DATA, ARGV, ARGVOUT. Die „Datei“ Tastatur wird beim Starten eines Programms automatisch geöffnet und ist über den Filehandle STDIN während des ganzen Programms ansprechbar. Beispiel 2.11: Einlesen vom Terminal Folgende Anweisung liest vom Terminal einen String und speichert ihn unter der skalaren Variable $str ab: print (" Bitte geben Sie einen String ein > > >"); $str = < STDIN >; # oder $str = < > print (" Die Eingabe war $str ,"); print (" Ende "); 2.8. Ausdrücke 21 Der Benutzer startet das Perl Programm, es erscheint der Text Bitte geben Sie einen String ein >>> Der Benutzer gibt folgenden String am Terminal ein Hallo Damit des Perl Programm die Eingabe bearbeitet, muss der Benutzer nach der Eingabe der Buchstaben die RETURN Taste drücken. Der Benutzer hat also folgendes eingegeben: Hallo < return > Daraufhin beginnt Perl die eingegebenen Daten zu bearbeiten. Perl liest die eingegebenen Buchstaben, inklusive des RETURN Zeichens vom Terminal und weist die gelesenen Buchstaben der Variablen zu. Perl speichert somit die Eingabe "Hallo" inklusive des RETURN Zeichens. Das Return Zeichen wird intern als special Character \n (=newline) Zeichen in $str abgespeichert. Dies ergibt folgenden Speicherinhalt: $str = H a l l o \ n Bei der Ausgabe eines Strings wird der \n Buchstabe wieder als Zeilenumbruch interpretiert, so dass die Ausgabe des Strings \$str folgende Ausgabe auf dem Terminal erzeugt: Die Eingabe war Hallo , Ende Da der Benutzer im allgemeinen nur an den eingegeben Zeichen, nicht aber am \n Zeichen interessiert ist, gibt es in Perl die spezielle Funktion: chomp ( ... ); die ein \n Zeichen am Ende des Strings entfernt. Das Programm dazu lautet: print (" Bitte geben $str = < STDIN >; # Im String steht chomp ( $str ); # Im String steht print (" Die Eingabe print (" Ende \ n "); Sie einen String ein > > >"); # Eingabe von " Hallo < RETURN >" " Hallo \ n " # Entfernt \ n am Ende des Strings " Hallo " war $str ,"); Das Programm liefert folgende Ausgabe: Die Eingabe war Hallo , Ende 22 2. Die Programmiersprache Perl Beispiel 2.12: Arbeit mit Variablen #!/ usr / bin / perl # file :/ DieSprache / vardeklaration . perl # Demonstration von Skalaren und Listen use strict ; { my $x ; my $y ; my $a ; my $b ; my $c ; my $anz_buchst ; my $name ; my $farbe ; my $s_farbe ; my @namen ; my @werte ; my @eintrag ; my @buchstaben ; print (" Demonstration SKALARE , LISTEN \ n "); $x $y $farbe @namen @werte @eintrag print (" print (" print (" print (" print (" print (" = = = = = = 1; 2.4; " rot "; ( " max " , " moni " , " sepp " ); ( 1 , 2 , 3 , 4 , 5 , 6 ); ( " Moni " , " Müller " , 29 , 10 , 1972 ); x = $x \ n "); y = $x \ n "); Farbe = $farbe \ n "); Name = @namen \ n "); Werte = @werte \ n "); Eintrag = @eintrag \ n "); # # mit Umlauten : # print (" Demonstration Umlaute \ n "); $s_farbe = " grün "; print (" Eine schöne Farbe ist $s_farbe \ n "); } # # Einlesen von Skalaren : # print (" Bitte geben Sie eine Zahl ein > > >"); $x = < STDIN >; chomp ( $x ); print (" Danke , Die Eingabe war : $x \ n "); print (" Bitte geben Sie eine Farbe ein ( Auch mit Umlauten ) > > >"); $s_farbe = < STDIN >; chomp ( $s_farbe ); print (" Danke , Die Eingabe war : $s_farbe \ n "); 2.9. Operatoren 23 2.9. Operatoren Mit Hilfe von Operatoren können Ausdrücke geschaffen werden, die Variablen oder Konstanten ihrer Definition entsprechend verknüpfen: z.B. <operand> $zahl1 <operator> * <operand> $zahl2 Für jeden internen Datentyp gibt es genau festgelegte Operatoren. Achtung: Die Kombination falscher Operanden und Operatoren führt in Perl meist zu Rechenfehlern, nicht aber zum Programmabsturz. 2.9.1. arithmetische Operatoren + * / % modulo 2.9.2. string Operatoren In Perl wird der interne Standardtyp string vom internen numerischen Standardtyp unterschieden. Für Strings und für Zahlen gibt es eigene Operatoren. Beachten Sie, dass sprachspezifische Eigenheiten nur berücksichtigt werden, wenn „use locale“ verwendet wird. Zur Konkatenation zweier Strings gibt es den K o nk at en ati on so per at or . Zur Vervielfältigung von Strings gibt es den V e r v i e l f ä l t i g u n gs o p e r a t o r x Beispiel 2.13: string Operatoren my $a =" AAA "; my $b =" BBB "; my $c ; Konkatenieren von $a und $b: $c = $a . $b ; ergibt : $c = " AAABBB " Vervielfältigung von a : $c = $a x 3; ergibt : $c = " AAAAAAAAA " 2.9.3. Grundlagen: Logische Ausdrücke Aussagen, denen man einen Wahrheitswert, nämlich wahr oder falsch zuordnen kann, bezeichnet man als logische Aussagen. Eine Aussage hat den Wahrheitswert wahr (true) falls sie zutrifft und falsch (false) falls sie nicht zutrifft. Bei der Auswertung von beliebigen logischen Aussagen hilft die Theorie der Aussagenlogik. Sei W(A) der Wahrheitswert der Aussage A: W ( A ) = true , falls die Aussage A wahr ist W ( A ) = false , falls die Aussage A falsch ist 24 2. Die Programmiersprache Perl Logische Ausdrücke können mit Hilfe von Logischen Operatoren aus Primitiven Objekten gebildet werden. Zum Vergleich von Zahlen und Buchstaben gibt es je 6 Vergleichsoperatoren, die in der Tabelle 2.2 gezeigt werden. Operator für Zahlen Operator für Name Buchstaben und Buchstabenfolgen (Zeichenketten) Beispiel == eq gleich != < <= > >= ne lt le gt ge ungleich kleiner kleiner gleich größer größer gleich 1 == 2 ’a’ eq ’b’ a != 4 2 < 3 2 <= 3 4 > 5 4 >= 5 Negation != == >= > <= < Tabelle 2.2.: Logische Operatoren Aussagen können mit UND (and, &&) bzw. ODER (or, ||) verknüpft werden. Aussagen können mit NEIN (not, !) negiert werden. • Es gilt Aussage (A) and Aussage (B), falls Aussage (A) UND Aussage (B) gelten. • Es gilt Aussage (A) or Aussage (B), falls Aussage (A) ODER Aussage (B) gelten. Bei der Auswertung von logischen Aussagen helfen sogenannte Wahrheitstafeln, die in der Tabelle 2.3 abgebildet sind. Aussage Aussage A B true true false false true false true false UND A and B A && B true false false false ODER A or B A || B true true true false Negation not (A) !(A) false false true true Tabelle 2.3.: Logische Aussagen 2.9.4. Vergleichsoperatoren Vergleichsoperatoren können Werte logisch vergleichen. Ob zum Beispiel eine Zahl kleiner ist als eine andere oder ein String identisch zu einem anderen ist. In Perl muss man je nachdem ob numerische oder string Werte verglichen werden den zuständigen Vergleichsoperator verwenden, wie sie in der Tabelle 2.4 sehen. Für die Beispiele gilt: my my my my $a $b $str1 $str2 = = = = 1; 2; " abcs "; " abdede "; 2.9. Operatoren 25 Operator für numerische Werte Operator für string Werte Name == eq gleich != ne ungleich < <= lt le kleiner kleiner gleich > gt größer >= ge größer gleich Beispiel Negation $a == $b "abc"eq $str1 ! $a ne $str $a < 3 2 <= 3 $a > 5 $str > ’abc’ 4 >= 5 != == >= > <= < Tabelle 2.4.: Vergleichsoperatoren Beispiel 2.14: Vergleichsoperatoren bei ganzen Zahlen #!/ usr / bin / perl # file :/ DieSprache / verOpZahlen . perl # Demonstration von Vergleichsoperatoren bei Zahlen use strict ; { my $eingabe = 0; my $nummer = 5; } if ( $eingabe != $nummer ) { print (" Bitte raten Sie eine Nummer zwischen 0 und 9\ n "); print (" Bitte Eingabe der Nummer > > >"); $eingabe = < STDIN >; chomp ( $eingabe ); if ( $eingabe != $nummer ) { print (" Ha , Ha , Ha , Eingabe war falsch \ n "); } } Beispiel 2.15: Vergleichsoperatoren bei Strings #!/ usr / bin / perl # file :/ DieSprache / verOpString . perl # Demonstration von Vergleichsoperatoren bei Strings use strict ; { my $eingabe = ""; my $wochentag = " Montag "; print (" Bitte raten Sie einen Wochentag \ n "); print (" Bitte Eingabe des Wochentags > > >"); $eingabe = < STDIN >; chomp ( $eingabe ); if ( $eingabe ne $wochentag ) { print (" Ha , Ha , Ha , Eingabe war falsch \ n "); } if ( $eingabe lt $wochentag ) { print (" Ein Tipp : Ihre Eingabe war alphabetisch kleiner \ n "); } if ( $eingabe gt $wochentag ) { print (" Ein Tipp : Ihre Eingabe war alphabetisch größer \ n "); } else { 26 2. Die Programmiersprache Perl } print (" Endlich !!!\ n "); } print ( " Ihre Eingabe war $eingabe \ n " ); print ( " Der Wochentag war $wochentag \ n " ); In Perl sind folgende Werte in einem logischen Ausdruck wahr (siehe 2.5) : Wert=wahr 1 "␣" "hello" Beispiel my $i = 1; if ($i) { my $i = "␣"; if ($i) { my $i = "hello"; if ($i) { Beschreibung Der numerische Wert 1 ist immer true Das Leerzeichen als string ist immer true Jeder String ist immer true Tabelle 2.5.: Wahre Werte in einem logischen Ausdruck In Perl sind folgende Werte in einem logischen Ausdruck falsch (siehe 2.6) : Wert = falsch 0 "" "0" Beispiel my $i = 0; if ($i) { my $str = ""; if ($str) { my $str = "0" if ($i) { Beschreibung Der numerische Wert 0 ist immer "false" Der leere String ist immer false Jeder String mit dem einzigen Buchstaben 0 (Null) ist immer false Tabelle 2.6.: Falsche Werte in einem logischen Ausdruck 2.10. Kontrollstrukturen 27 2.10. Kontrollstrukturen Die Kontrollstrukturen kontrollieren den Ablauf des Programms. Sie verändern den Wert von Variablen und bestimmen die Reihenfolge der Anweisungen, die im Programm ausgeführt werden sollen. in Perl gibt es folgende Kontrollstrukturen: • einfache Zuweisungen, Statements • Blöcke : eine Anzahl von Statements die geklammert sind : { ... } • Ablaufsteuerungsanweisungen: if if else while do while do until foreach for und weitere • Subroutinen 2.10.1. Blöcke Möchte man Ausdrücke zu einem einzigen Ausdruck zusammenfassen, muss man die Ausdrücke mit geschweiften Klammern zusammenfassen. Vor der ersten Anweisung muss eine öffnende geschweifte Klammer stehen, nach der letzten Anweisung eine schließende geschweifte Klammer. Geklammerte Ausdrücke nennt man Block oder compound statement. Am Anfang eines jeden Blocks können Variablen definiert werden, die nur innerhalb dieses Blocks gelten. Formatierungskonvention: • Öffnende geschweifte Klammer in Blockeinleitungszeile • Schließende geschweifte Klammer separat in der nächsten Zeile hinter der letzten Anweisung. Die Einrücktiefe ist die gleiche wie die des ersten Zeichens des Blockeinleitungsstatements • Die Anweisungen innerhalb des Blocks werden eingerückt und stehen untereinander • Zur Einrückung keine Tabstops verwenden! Einrückung mit 2 oder 3 Leerzeichen (die meisten grafischen Editoren unterstützen das Feature: Obwohl sie bei diesen Editoren die Tabulatortaste drücken, werden in der Datei Leerzeichen eingefügt. Die Einrücktiefe wird im gesamten Programm bei Blöcken beibehalten.) Beispiel 2.16: Blöcke #! usr / bin / perl use strict ; { my $a ; 28 2. Die Programmiersprache Perl } my $zahl my $wert $a $wert = = = = 100; 1; $zahl ; 2; 2.10.2. Auswahlanweisung: if if ( Expression ) { Anweisungen } Die Expression muss ein auswertbarer logischer Ausdruck sein. Falls der Wert der Expression wahr ist (siehe: Definition von Wahrheitswerten) werden die Anweisungen innerhalb des Blocks ausgeführt. Ist der Wert der Expression falsch, dann werden die Anweisungen übersprungen und die Anweisungen hinter der geschweiften Klammer ausgeführt. Falls die Anweisungen nur aus einer Anweisung bestehen, dann kann an der Stelle der geklammerten Anweisungen auch ein einzelnes Statement stehen. 2.10.3. Auswahlanweisung: if...else if ( Expression ) { Anweisungen1 } else { Anweisungen2 } Die Expression muss ein auswertbarer logischer Ausdruck sein. Falls der Wert der Expression wahr ist, werden Anweisungen1 ausgeführt, sonst Anweisungen2 Formatierungskonvention: • die Anweisungen werden mit einer geschweiften Klammer in der Zeile der if-Anweisung geöffnet • die Anweisungen werden 2-4 Zeichen eingerückt, die Einrücktiefe wird im gesamten Block beibehalten • die Anweisungen stehen untereinander • jede Anweisung steht in einer eigenen Zeile • schließende geschweifte Klammer separat in der nächsten Zeile hinter der letzten Anweisung. Die Einrücktiefe ist die gleiche wie die der if -Anweisung • eine eventuelle else Anweisung wird hinter der schließenden Klammer der if-Anweisung fortgesetzt • nachfolgende Anweisungen werden wie bei der if-Anweisung geklammert Beispiel 2.17: if Anweisung #!/ usr / bin / perl # Demonstration der if - Anweisung use strict ; { if ( $i == 0) { print (" Ich bin gleich Null \ n "); } 2.10. Kontrollstrukturen } 29 if ( $i == 2) { print (" i ist gleich 2 "); } else { print (" i ist ungleich 2"); $i = 0; } 2.10.4. Wiederholungsanweisung: while while ( Expression ) { Anweisungen } Die Expression muss ein auswertbarer logischer Ausdruck sein. Falls der Wert der Expression true ist, werden die Anweisungen innerhalb der geschweiften Klammer solange ausgeführt, bis der Wert der Expression false ist. Formatierungskonvention: • die Anweisungen werden mit einer geschweiften Klammer in der Zeile der whileAnweisung geöffnet • die Anweisungen werden 2-4 Zeichen eingerückt, die Einrücktiefe wird im gesamten Programm bei Blöcken beibehalten • die Anweisungen stehen untereinander • jede Anweisung steht in einer eigenen Zeile • schließende geschweifte Klammer separat in der nächsten Zeile hinter der letzten Anweisung. Die Einrücktiefe ist die gleiche wie die der while-Anweisung Beispiel 2.18: while Anweisung #!/ usr / bin / perl # file :/ DieSprache / whileAnweisung . perl # Demonstration von while - Anweisung use strict ; { my ( @glueckszahlen , $zahl , $zaehler ); $zaehler = 0; print (" Geben Sie bitte Ihre 5 Glückszahlen ein :\ n "); while ( $zaehler < 5 ) { $glueckszahlen [ $zaehler ] = < >; $zaehler ++; } print (" Danke !\ n "); print (" Geben Sie eine Zahl ein , ich sage , ob es eine Glückszahl ist :\ n "); $zahl = < >; chomp ( $zahl ); } while ( $zaehler >= 0 && $glueckszahlen [ $zaehler ] != $zahl ) { $zaehler - -; } if ( $zaehler == -1 ) { print (" $zahl ist keine Glückszahl \ n "); } else { print (" Ja , $zahl ist eine Glückszahl !\ n "); } 30 2. Die Programmiersprache Perl Beispiel 2.19: while Anweisung #!/ usr / bin / perl # Demonstration der while - Anweisung use strict ; { my $i = 0; while ( $i <10) { print (" Zahl = "); print (" $i \ n "); $i = $i +1; } } Beispiel 2.20: eine Zahl raten Das Programm fordert den Benutzer auf, eine intern definierte Zahl zu erraten. Falls die Zahlen nicht identisch sind, gibt es eine Fehlermeldung aus, aus der hervorgeht, ob die eingegebene Zahl größer oder kleiner als die intern gespeicherte Zahl ist. Sind sie identisch, dann soll eine Erfolgsmeldung ausgegeben werden. Der Benutzer wird nur maximal fünfmal gefragt. #!/ usr / bin / perl # file :/ DieSprache / zahlRaten . perl # Zahl erraten use strict ; { my ( $zaehler , $zahl , $geraten , $versuche ); } $zaehler = 0; $zahl = 5; print (" Rate die Zahl !\ n "); $geraten = < >; while ( ( $zaehler < 4 ) && ( $geraten != $zahl ) ) { if ( $geraten > $zahl ) { print (" Die eingegebene Zahl ist groesser als die gespeicherte !\ n "); } else { print (" Die eingegebene Zahl ist kleiner als die gespeicherte !\ n "); } $versuche = 4 - $zaehler ; print (" Verbleibende Versuche : $versuche \ n "); print (" Probiers nochmal : "); $geraten = < >; $zaehler ++; } if ( $geraten == $zahl ) { print (" Erraten !\ n "); } else { print (" Nicht erraten !\ n "); } 2.10. Kontrollstrukturen 31 2.10.5. Wiederholungsanweisung: do while do { Anweisungen } while ( Expression ) Die Expression muss ein auswertbarer logischer Ausdruck sein. Der Block wird solange ausgeführt, wie der Wert von Expression true ist. Formatierungskonvention: • die Anweisungen werden mit einer geschweiften Klammer in der Zeile der doAnweisung geöffnet • die Anweisungen werden 2-4 Zeichen eingerückt • die Anweisungen stehen untereinander • jede Anweisung steht in einer eigenen Zeile • schließende geschweifte Klammer separat in der nächsten Zeile hinter der letzten Anweisung. Die Einrücktiefe ist die gleiche wie die do-Anweisung • dahinter steht die while Anweisung mit dem logischen Ausdruck Expression Beispiel 2.21: do while Anweisung #!/ usr / bin / perl # Demostration der do - while - Anweisung use strict ; { my $i = 20; print (" Ich gebe alle geraden Zahlen zwischen 20 und 0 aus \ n "); do { print (" Zahl = "); print (" $i \ n "); $i = $i -2; } while ( $i >= 0) } 2.10.6. Wiederholungsanweisung: do...until do { Anweisungen } until ( Expression ) Die Expression muss ein auswertbarer logischer Ausdruck sein. Der Block wird solange ausgeführt, bis der Wert von Expression true ist. Formatierungskonvention: • wie bei der do ... while Anweisung Beispiel 2.22: do until Anweisung #!/ usr / bin / perl # Demonstration von do - until - Anweisung use strict ; { my $i = 0; 32 2. Die Programmiersprache Perl } do { print (" Zahl = "); print (" $i \ n "); $i = $i +1; } until ( $i > 10) Der Unterschied zwischen while . . . und do . . . liegt darin, dass bei while zuerst die Bedingung geprüft wird und dann der Block ausgeführt wird. Bei do . . . wird zuerst der Block ausgeführt und dann die Bedingung geprüft. Die while Schleife terminiert dann, wenn die Auswertung der Expression den logischen Wert false ergibt. Die do Schleife terminiert genau beim logischen Gegenteil: Die Auswertung von Expression muss true ergeben, damit die do Schleife terminiert. 2.10.7. Wiederholungsanweisung: foreach foreach $element ( @liste ) { Anweisungen } 2.10.8. Wiederholungsanweisung: for for ( $i =0; $i <5; $i ++) Anweisungen } { Beispiel 2.23: foreach und for Anweisung #!/ usr / bin / perl # Demonstration von foreach und for Anweisung use strict ; { my @numbers = (2 ,4 ,6 , -10 ,12); my $i ; foreach $i ( @numbers ) { print (" Zahl = $i \ n "); } for ( $i =0; $i <5; $i ++) { print (" $i te Zahl = $numbers [ $i ] \ n "); } } for ( $i =4; $i >=0; $i - -) { print (" $i te Zahl = $numbers [ $i ] \ n "); } Es werden der Reihe nach die Elemente aus der Liste @liste der Variablen $element zugewiesen. Dann wird jedesmal der Block mit dem entsprechenden Variablenwert ausgeführt. Beispiel 2.24: Liste #!/ usr / bin / perl # Beispiel für Array use strict ; { my @farben = (" rot " ," gruen " ," blau "); my $farbe ; foreach $farbe ( @farben ) { print (" Farbe = $farbe \ n "); } } 2.11. Lesen von Daten aus einer Datei 33 2.11. Lesen von Daten aus einer Datei Zur permanenten Speicherung von Daten verwendet man in Betriebssystemen Dateien. Dateien werden über einen Namen innerhalb eines Verzeichnisses (Ordner) eindeutig identifiziert. Unter UNIX werden Dateien, die binäre Daten speichern, Binärdateien und Dateien, die Texte speichern, Textdateien genannt. Unter UNIX wird eine Textdatei als geordnete Folge oder „Strom“ stream von Zeichen (Bytes) betrachtet. Die einzelnen Zeilen sind durch ein Zeilentrennzeichen (’\n’) getrennt. Beispiel 2.25 Folgende 5 Zeilen werden mit einem Texteditor in die neue Datei file.txt geschrieben: Eins Zwei Drei 4 5 6 7 8 Ende Damit die Information des Zeilenumbruchs nicht verloren geht, wird in der Datei an die Stelle des Zeilenumbruchs ein sogenannter Special Character eingefügt. Dieser Special Character hat die Aufgabe bei der Ausgabe einen Zeilenumbruch zu bewirken. Der Special Character hat bei UNIX den Octal Code 12 und heißt Newline (Abkürzung = nl) Aus diesen Gründen wird auf der Festplatte der Inhalt folgendermaßen Zeichen für Zeichen abgespeichert: E i n s nl Z w e i nl D r e i nl 4 sp 5 sp 6 sp 7 sp 8 nl E n d e wobei sp die Kodierung für Space und nl die Kodierung für newline ist. Unter UNIX gibt es den Befehl od (Octal Dump) mit dem man den Inhalt einer Datei Zeichen für Zeichen darstellen (=„dumpen“) kann. Dem Befehl muss man angeben, mit welchem Format die Zeichen der Datei konvertiert werden sollen, bevor sie auf dem Terminal ausgegeben werden. In der linken Spalte gibt der Befehl od die octale Bytenummer des ersten Zeichens in der Datei aus, in den restlichen Spalten die Zeichen entsprechend der ausgewählten Konvertierung. (Zur weiteren Information zum Befehl od geben Sie den UNIX Befehl „man od“ ein.) Beispiel 2.26: Ausgabe der Zeichen als OKTAL-Wert > od -b file . txt 0000000 105 151 156 163 012 132 167 145 151 012 104 162 145 151 012 064 0000020 040 065 040 066 040 067 040 070 012 116 145 165 156 012 105 156 0000040 144 145 0000042 Beispiel 2.27: Ausgabe der Zeichen als ASCII-Wert > od -a file . txt 0000000 E i 0000020 sp 5 0000042 n sp s 6 nl sp Z 7 w sp e 8 i nl nl E D n r d e e i nl 4 Befehle zur Ausgabe von Textdateien interpretieren die nl Zeichen bei der Ausgabe auf das Terminal richtig und erzeugen einen Zeilenumbruch anstelle des Buchstabens nl. 34 2. Die Programmiersprache Perl Beispiel 2.28: Textbefehl cat zur Ausgabe einer Textdatei > cat file . txt Eins Zwei Drei 4 5 6 7 8 Ende 2.11.1. Dateihandles Möchte man den Inhalt der Datei in einem Perl Programm lesen, dann muss die Datei im Perl Programm einem internen Dateihandle zugewiesen werden. Außerhalb des Progamms Filename Innerhalb des Programms Filehandle Die Perlfunktion „open“ ordnet einer externen Datei einen internen Dateihandle zu und setzt den Filepositionmarker auf den Anfang. open ( filehandle , filename ) Zum Lesen der nächsten Zeichen hinter dem Filepositionmarker gibt es den sogenannten Diamond-operator. < filehandle > Beispiel 2.29 open ( DATEI ," file . txt ") Am Ende eines Programms muss der Filehandle wieder geschlossen werden: close DATEI ; Der Diamond-operator liefert als Ergebnis alle Zeichen aus der Datei die nach dem Filepositionmarker folgen, bis zum nächsten Zeilentrennzeichen (’\n’). Nach erfolgreichem Lesen wird der Filepositionmarker hinter das zuletzt gelesene Zeichen gesetzt. Falls der Filepositionmarker am Ende der Datei steht, wird bei erneutem Aufruf des Diamond-operators ein leerer String zurückgeliefert. Beispiel 2.30: Zeilenweises lesen aus der Datei „file.txt“ #!/ usr / bin / perl # file :/ DieSprache / file . perl # Demonstration Lesen aus einer Textdatei use strict ; { my $filename = " file . txt "; my $line ; open ( EINGABE , $filename ); while ( $line = < EINGABE > ) { chomp $line ; # empfehlenswert zum Löschen des Zeilenumbruchs print " $line \ n "; } close ( EINGABE ); } Test mit der Datei zeilen.txt Der Inhalt ist: 2.11. Lesen von Daten aus einer Datei 35 Erste zweite Nach dem Öffnen wird dem Filehandle EINGABE die Datei „zeilen.txt“ zugeordnet. Der Filepositionmarker (!pos) steht am Anfang. E r s t e !pos Lesen der ersten Zeile ergibt: \n z w e i t e \n $line = " erste \ n "; Der Filepositionmarker wird hinter den letzten gelesenen Buchstaben positioniert: E r s t e \n z w e i t e \n !pos Lesen der zweiten Zeile ergibt: $line = " zweite \ n "; Der Filepositionmarker wird hinter den letzten gelesenen Buchstaben positioniert E r s t e \n z w e i t e \n !pos Lesen der nächsten Zeile ergibt: $line = ""; Es wird nichts gelesen. Der Diamondoperator liefert den leeren String. Der Inhalt von $line wird auf Null gesetzt, die while Schleife terminiert ! Beispiel 2.31: Kopie einer Datei erzeugen Das Programm erfragt den Namen einer Datei und erzeugt eine Kopie dieser Datei mit dem Namen kopie.txt: #!/ usr / bin / perl # file :/ DieSprache / dateiCopy . perl # Kopieren einer Textdatei use strict ; { my ( $dateiname , $ausgabe , $zeile ); $ausgabe = " kopie . txt "; print (" Bitte geben Sie einen Dateinamen ein , zum Kopieren der Datei > > > "); $dateiname = < STDIN >; chomp $dateiname ; open ( DATEI , $dateiname ); open ( AUSGABE , " > $ausgabe " ); while ( $zeile = < DATEI > ) { # kein chomp , damit Zeilenumbrueche erhalten bleiben print AUSGABE $zeile ; } } close DATEI ; close AUSGABE ; 36 2. Die Programmiersprache Perl 2.12. Interne Repräsentation von Zahlen Das Dezimalsystem: Wenn wir eine Zahl, z.B: 253 lesen, gehen wir zunächst automatisch davon aus, dass es sich um eine Zahl des Dezimalsystems handelt. Im Zehnersystem wird mit 10 verschiedenen Ziffern gearbeitet, die durch die Ziffern 0-9 ausgedrückt werden. Wir lesen die Ziffern nach folgendem Schema: Einer: 100 Zehner: 101 Hunderter: 102 usw. Daraus ergibt sich für die Zahl 253 folgende Darstellung: 2·102 + 5·101 + 3·100 = 253 Analog geht man auch bei anderen Zahlensystemen vor, nur benutzt man andere Werte als Basis: Das Binärsystem: Im Gegensatz zum Dezimalsystem, bei dem die Basis 10 verwendet wird, nimmt man beim Binärsystem die Basis 2 (=Übersetzung in Binärcode). Gültige Ziffern sind die 0 und die 1. Sollen nur positive ganze Zahlen dargestellt werden, kann man mit n Bit (Stellen) die Zahlen von 0 bis 2n−1 darstellen. Die größte Zahl ist also 2n . Darstellungen zu unterschiedlichen Basen: Beispiel 2.32: Binärdarstellung von einer Dezimahlzahl Dezimalzahl 1 · 20 1 · 21 + 0 · 22 + 1 · 23 11 = = = = = = Binärzahl 1011 1 2 0 8 11 Darstellung negativer Werte: Vorzeichenbit: das erste Bit zeigt das Vorzeichen an: 1 ist negativ, 0 ist positiv Zweier Komplement : bt − x = 1 + t−1 P i=0 (b − 1) · bi − wird als (bt ) - x dargestellt. t−1 P i=0 ai · bi = 1 + t−1 P i=0 Darstellung im Zweierkomplement der Zahlen -4 bis +3: -4 -3 -2 -1 = = = = 100 101 110 111 0 1 2 3 = = = = 000 001 010 011 (b − 1 − ai ) · bi 2.12. Interne Repräsentation von Zahlen 37 Darstellung reeller Werte: x = m · be , e ganze Zahl m ist die Mantisse, e der Exponent. Erklärung: Die Mantisse ist die Ziffernstelle einer Gleitkommazahl. Beispiel 2.33 Bei der Zahl 5,5 · 103 ist 5,5 die Mantisse, 3 der Exponent. Beispiel 2.34 Dezimalzahl : 53 , Dezimalzahl : 63 , binäre Darstellung : 110101 binäre Darstellung : 111111 Das Oktalsystem: In diesem System verwendet man die Basis 8, es sind die Ziffern 0,1,2,3,4,5,6,7 gültig. Beispiel 2.35 Die Zahl 136 z.B. wird dargestellt als 2 · 82 + 1 · 81 + 0 · 80 = 210 als Oktalzahl 53(dezimal) = 65(oktal) = 6 · 81 + 5 · 80 63(dezimal) = 77(oktal) = 7 · 81 + 7 · 80 136 (dezimal) = 210(oktal) = 6 · 81 + 5 · 80 Das Hexadezimalsystem: Beim Hexadezimalsystem wird die Zahl 16 als Basis zu Grunde gelegt. Für dieses System benötigt man 16 Ziffern, es werden zu den Ziffern 0-9 für die fehlenden 6 Ziffern die Buchstaben A-F verwendet. Gültige „Ziffern“: 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F Die Zahl 136 z.B. wird dargestellt als 8 · 161 + 8 · 160 Das Hexadezimalsystem wird häufig verwendet, da es sich letztlich um eine komfortable Schreibweise des Binärsystems handelt. Es eignet sich durch seine Basis der vierten Zweierpotenz (16 = 24 ) zur relativ einfachen Darstellung von Binärzahlen. Ein Byte mit 8 Bit lässt sich in ein Halbbyte mit 4 Bit aufteilen. Das heißt, man kann ein Byte mit zwei Stellen im Hexadezimalsystem darstellen. Beispiel 2.36 53( dezimal ) 63( dezimal ) = = 35( hexadezimal ) 3 F ( hexadezimal ) Beispiel 2.37: Darstellung der Dezimalzahl 60 im Speicher 60/2 = 30 30/2 = 15 15/2 = 7 7/2 =3 3/2 =1 1/2 =0 das entspricht Rest Rest Rest Rest Rest Rest 0 0 1 1 1 1 (Wertigkeit (Wertigkeit (Wertigkeit (Wertigkeit (Wertigkeit (Wertigkeit 0.Stelle) 1.Stelle) 2.Stelle) 3.Stelle) 4.Stelle) 5.Stelle) :| 1 | 1 | 1 | 1 | 0 | 0 | 38 2. Die Programmiersprache Perl Beispiel 2.38: Darstellung der Zahl 60 als Oktalzahl im Speicher 60/8 7/8 | =7 =0 7 | Rest 4 Rest 7 4 12 (dezimal) 256 (dezimal) 64(dezimal) (Wertigkeit 0.Stelle) (Wertigkeit 1.Stelle) | 1100 (binär) 100000000 (binär) 1000000 (binär) 14 (oktal) 400 (oktal) 100 (oktal) C (hexadezimal) 100 (hexadezimal) 40 (hexadezimal) 2.13. Interne Repräsentation von Schriftzeichen In der Tabelle 2.7 werden 7-bit-Codes für ASCII Buchstaben dargestellt. 2.13.1. Speicherung von Strings Unter Strings (=string literale) werden in Perl Folgen von Buchstaben verstanden. Die Buchstaben, die den String repräsentieren, müssen in Double Quotes zusammengefasst werden. Im Speicher werden die Buchstaben entsprechend der ASCII oder UNICODE Kodierung als ganzzahlige Werte einzeln der Reihe nach abgespeichert. Jeder String kennt die Anzahl seiner Buchstaben. 2.13.2. Speicherung von Buchstaben Da Buchstaben nicht direkt im Speicher abgebildet werden, wird jedem Zeichen (Buchstaben) eine ganze Zahl (Zeichencode) zugeordnet. Die Abbildung Buchstabe ⇒ Nummer wurde im American National Standard Code for Information Interchange (ASCII) definiert, wobei dieser Code in den ersten Versionen nur 7 Bit Zahlen verwendete. Somit konnte diese Codierung nur 128 Zeichen kodieren, siehe Tabelle 2.7 2.13. Interne Repräsentation von Schriftzeichen 39 2.13.3. Zeichencodierung: ASCII, für Buchstaben, mit 7 Bit 000 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ! " # $ % & ’ ( ) * + , . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ˆ _ 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ‘ a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ • Tabelle 2.7.: Zeichencodierung: ASCII, für Buchstaben, mit 7 Bit 2.13.4. Bedeutung der Steuerzeichen Die Buchstaben mit ASCII Code kleiner als 31 werden Steuerzeichen genannt und zur Formatierung von Texten oder Ausgaben verwendet. Beispiel 2.39 Es ist folgender String gegeben : " abcd " , Stringlänge ist 4 Liegt eine ASCII-Kodierung vor, dann wird die Zeichenkette als Folge von 4 ganzen Zahlen (7-Bit Zahlen), entsprechend der ACSII-Codierung abgespeichert: 97,98,99,100 (Darstellung als Dezimalzahl) 40 Layout bs ht lf vt ff cr 2. Die Programmiersprache Perl Characters: backspace horizontal Tabulation linefeed vertical tabulation form feed carriage return Escape Characters: so shift-out si shift-in esc escape Medium Characters: bel bell ring dc1-dc4 device controll em end of medium Ignore characters: nul null character can cancel sub substiute del delete Communication Characters: soh start of heading stx start of text etx end of text eot end of transmission enq enquiry ack acknowledgement nak negative acknowledgement dle data link escape syn synchronous idle etb end of transmission block Seperator characters: fs fileseperator gs group seperator rs record seperator us unit seperator Tabelle 2.8.: Bedeutung der Steuerzeichen 2.13.5. Zeichencodierung: ISO Latin-1 für Buchstaben, 8 Bit Für länderspezifische Buchstaben fand sich im ASCII-Code kein Zeichencode mehr. Versuche, den ASCII-Code auf 8 Bit zu erweitern, scheiterten daran, dass kein gemeinsamer Standard für die Buchstabennummern gefunden wurde. Erst der ISO (=International Standardization Organization) gelang es den Buchstabencode auf 8 Bit zu erweitern und länderspezifische Buchstaben zu standardisieren. Die ISO definierte für verschieden Sprachfamilien verschiedene Zeichenkodierungen. Für die lateinischen Buchstaben definierten sie z.B. ISO-LATIN. Um auch Buchstaben zu kodieren, die nicht lateinisch sind, wurden von der ISO weitere länderspezifische Zeichencodes entwickelt, z.B. für die griechischen Buchstaben ISO-Greek. Die folgende Tabelle zeigt die Definitionen des ISO-Latin-1 Character Set oder auch ISO8859-1. Description ================== quotation mark ampersand less-than sign greater-than sign Description ================== non-breaking space inverted exclamation cent sign pound sterling Char ==== ¡ ¢ £ Code ========== " → " & → & < → < > → > Entity name ============ " → " & → & < → < > → > Code ============  → ¡ → ¡ ¢ → ¢ £ → £ Entity name ============ → ¡ → ¡ ¢ → ¢ £ → £ 2.13. Interne Repräsentation von Schriftzeichen 41 general currency sign yen sign broken vertical bar ¤ ¥ ¦ ¤ → ¤ ¥ → ¥ ¦ → ¦ section sign umlaut (dieresis) § ¨ § → § ¨ → ¨ copyright feminine ordinal left angle quote, guillemotleft not sign soft hyphen registered trademark macron accent © ª « ¬ ® ¯ © ª « ¬ ­ ® ¯ →© →ª →« →¬ → →® →¯ degree sign plus or minus superscript two superscript three acute accent micro sign paragraph sign middle dot cedilla superscript one masculine ordinal right angle quote, guillemotright fraction one-fourth fraction one-half fraction three-fourths inverted question mark capital A, grave accent capital A, acute accent capital A, circumflex accent capital A, tilde capital A, dieresis or umlaut mark capital A, ring capital AE diphthong (ligature) capital C, cedilla capital E, grave accent capital E, acute accent capital E, circumflex accent capital E, dieresis or umlaut mark capital I, grave accent capital I, acute accent capital I, circumflex accent capital I, dieresis or umlaut mark capital Eth, Icelandic ° ± 2 3 ´ µ ¶ · ¸ 1 º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð →° →± →2 →3 →´ →µ →¶ →· →¸ →1 →º →» →¼ →½ →¾ →¿ →À →Á → →à →Ä →Å →Æ →Ç →È →É →Ê →Ë →Ì →Í →Î →Ï →Ð capital N, tilde capital O, grave accent Ñ Ò Ñ → Ñ Ò → Ò ¤ → ¤ ¥ → ¥ ¦ → ¦ &brkbar; → &brkbar; § → § ¨ → ¨ ¨ → ¨ © → © ª → ª « → « ¬ → ¬ ­ → ® → ® ¯ → ¯ &hibar; → &hibar; ° → ° ± → ± ² → 2 ³ → 3 ´ → ´ µ → µ ¶ → ¶ · → · ¸ → ¸ ¹ → 1 º → º » → » ¼ → ¼ ½ → ½ ¾ → ¾ ¿ → ¿ À → À Á → Á  →  à → Ã Ä → Ä Å → Å Æ → Æ Ç → Ç È → È É → É Ê → Ê Ë → Ë Ì → Ì Í → Í Î → Î Ï → Ï Ð → Ð Đ → Đ Ñ → Ñ Ò → Ò 42 2. Die Programmiersprache Perl capital O, acute accent capital O, circumflex accent capital O, tilde capital O, dieresis or umlaut mark multiply sign capital O, slash capital U, grave accent capital U, acute accent capital U, circumflex accent capital U, dieresis or umlaut mark capital Y, acute accent capital THORN, Icelandic small sharp s, German (sz ligature) small a, grave accent small a, acute accent small a, circumflex accent small a, tilde small a, dieresis or umlaut mark small a, ring small ae diphthong (ligature) small c, cedilla small e, grave accent small e, acute accent small e, circumflex accent small e, dieresis or umlaut mark small i, grave accent small i, acute accent small i, circumflex accent small i, dieresis or umlaut mark small eth, Icelandic small n, tilde small o, grave accent small o, acute accent small o, circumflex accent small o, tilde small o, dieresis or umlaut mark division sign small o, slash small u, grave accent small u, acute accent small u, circumflex accent small u, dieresis or umlaut mark small y, acute accent small thorn, Icelandic mall y, dieresis or umlaut mark Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ Ó → Ó Ô → Ô Õ → Õ Ö → Ö × → × Ø → Ø Ù → Ù Ú → Ú Û → Û Ü → Ü Ý → Ý Þ → Þ ß → ß à → à á → á â → â ã → ã ä → ä å → å æ → æ ç → ç è → è é → é ê → ê ë → ë ì → ì í → í î → î ï → ï ð → ð ñ → ñ ò → ò ó → ó ô → ô õ → õ ö → ö ÷ → ÷ ø → ø ù → ù ú → ú û → û ü → ü ý → ý þ → þ ÿ → ÿ Tabelle 2.9.: Definitionen des ISO-Latin-1 Character Set 2.13. Interne Repräsentation von Schriftzeichen 43 Lesen der Tabelle: 1. Spalte: 2. Spalte: 3. Spalte: 4. Spalte: Textliche Beschreibung des Buchstaben Darstellung des Buchstabes Buchstabencode wie er in HTML Texten als numerischer Entity geschrieben werden kann Buchstabencode wie er in HTML Texten als symbolischer Entity geschrieben werden kann Die Tabelle wurde entnommen von: Martin Ramsch’s „ISO 8859-1 Table“ Copyright: ©International Organization for Standardization 1986. Permission to copy in any form is granted for use with conforming SGML systems and applications as defined in ISO 8879, provided this notice is included in all copies. 2.13.6. Zeichenkodierung nach den Vorgaben des UNICODE Konsortium Der große Nachteil der ISO-Standardisierung ist, dass ähnlich wie bei ASCII nur einem Teil der sinntragenden Schriftzeichen bzw. Textelemente aller bekannten Schriftkulturen und Zeichensysteme ein Zahlencode zugeordnet wurde. Außerdem gab es bei den Zeichencodes keine Eindeutigkeit, da die Zuordnung des Zahlencodes zum Schriftzeichen von der eingestellten Sprachfamilie abhängig war: Zahlencode (Hexadezimal) C4 ISO Codierung ISO-Greek ISO-Latin ∆ (Delta) Ä (Umlaut Ä) Tabelle 2.10.: ISO Codierung Die Ambiguität löste das UNICODE Konsortium, indem es einen Universal Character Set (UCS) definierte. Der UCS reserviert für 1.114.112 Schriftzeichen Zeichencodes. Sie sollen für alle Schriftzeichen aller bekannten Schriftkulturen ausreichen. Die Bitbreite für die Zeichencodes wurde von 8 Bit auf 32 Bit erweitert. Sie definierten eine UNICODE Tabelle, in der jedem Schriftzeichen ein eindeutiger Zeichencode zugeordnet wurde: UNICODE Codierung Zahlencode (Hexadezimal) Zeichen 41 A 42 B C4 Ä (Umlaut Ä) 3FF ∆ (griechisches Delta) 22FF ∆ (mathematisches Delta) c39e þ(Grossbuchstabe ”Thorn”) Tabelle 2.11.: UNICODE Codierung Würde jetzt ein Text mit den vier Zeichen „ABBA“ abgespeichert, so wäre dies unter UNICODE mit der Folge von vier 32 Bit Zahlen realisiert: 0 0 0 0 0 0 0 0 0 0 0 0 41 42 42 41 44 2. Die Programmiersprache Perl Wir hätten also 4·4 Bytes = 16 Bytes in der Datei. Betrachtet man die 16 Bytes der Zeichencodes, so sieht man, dass nur 4 Bytes Informationen tragen, die anderen 12 Bytes sind Nullbytes. Als C-Programmierer weiß man, welche Probleme die Zahl Null in einem bytestream verursachen kann (Stichwort: File/ Stringende). Außerdem kann man auch von einer Platzverschwendung sprechen, da nur 4 Bytes die Information der Zeichencodes tragen. Daraufhin entwickelte Ken Thompson von den BELL Laboratories ein Transformationsformat, das in eindeutiger Weise die Zahlenfolge repräsentiert, aber nur die Bytes speichert, die die Informationen für die Zeichencodes tragen. Auf die Nullbytes verzichtet sein Verfahren. Das UNICODE – Konsortium übernahm dieses Verfahren und legte für jedes Schriftzeichen eine eindeutige Folge von Zahlen fest. Ein mitgelieferter Transformationsalgorithmus kann aus dieser Folge die eindeutige UNICODE-Zahl des zugrunde gelegten Schriftzeichens berechnen. Diese Kodierung nannten Sie „multibyte-Kodierung“. Aus „ABBA“ wurde wieder die Folge der 4 Bytes: 41 42 42 41 2.13.7. Die UTF Prinzipien Das UNICODE – Transformation Format (UTF) weist jedem Schriftzeichen eine eindeutige Folge von Zahlen zu, deren Bitbreite das Appendix „-n“ ausdrückt: UTF -6 ... eine Folge von 6 - Bit Zahlen UTF -8 ... eine Folge von 8 - Bit Zahlen (1 Byte ) UTF -16 ... eine Folge von 16 - Bit Zahlen (2 Bytes ) UTF -32 ... eine Folge von 32 - Bit Zahlen (4 Bytes ) Kennt der Transformations Algorithmus die Bitbreite der zugrundegelegten Codierung, dann kann er die eindeutige UNICODE-Nummer mit Hilfe von Bitoperationen sehr effizient berechnen (siehe nächstes Kapitel 3) Schriftzeichen A Ä ∆ UNICODE Nummer (Hexadezimal) 41 C4 394 utf-8 Byte Folge (Hexadezimal) 41 C3 84 CE 94 Der Text aus den drei Zeichen A, Ä und Delta ∆ : „AÄ∆“ wäre bei UTF-8 mit folgender Bytefolge abgespeichert: 41 C3 84 CE 94 Wie der Transformations-Algorithmus aus dieser Folge die Zeichennummer 41,C4 und 394 errechnet, wird im nächsten Kapitel erklärt. 2.13.8. Die UTF Kodierung im Detail aus http://de.wikipedia.org/wiki/UTF-8 (Abk. für 8-bit Unicode Transformation Format) ist die fortschrittlichste und populärste Kodierung für Unicode-Zeichen; dabei wird jedem Unicode-Zeichen eine speziell kodierte Bytekette von variabler Länge zugeordnet. Es unterstützt bis zu 4 Byte auf die sich wie bei allen UTF Formaten alle 1.114.112 Unicode Zeichen abbilden lassen. UTF-8 ist gegenwärtig als Request for Comments RFC 3629 standardisiert (UTF-8, a transformation format of ISO 10646). Dieser Standard löst das ältere RFC 2279 ab. Unicode-Zeichen mit den Werten aus dem Bereich von 0 bis 127 (0 bis 7F hexadezimal) werden in der UTF-8-Kodierung als ein Byte mit dem gleichen Wert wiedergegeben. Insofern sind alle Daten, die ausschließlich echte ASCII-Zeichen verwenden, in beiden Darstellungen identisch. Unicode-Zeichen größer als 127 werden in der UTF-8-Kodierung zu Byteketten der Länge zwei bis vier. 2.13. Interne Repräsentation von Schriftzeichen UnicodeBereich 45 UTF-8 Ko- Bemerkungen dierung 0000 0000 - 0xxxxxxx 0000 007F Möglichkeiten In diesem Bereich (128 Zei- 27 chen) entspricht UTF-8 genau dem ASCII-Code: Das erste Bit ist 0, die darauf folgende 7Bitkombination ist das ASCIIZeichen. 0000 0800 - 1110xxxx 0000 FFFF 10xxxxxx 10xxxxxx Das erste Byte beginnt mit binär 11, die folgenden Bytes beginnen mit binär 10; die x stehen für die fortlaufende Bitkombination des Unicodezeichens. Die Anzahl der Einsen bis zur ersten 0 im ersten Byte 0001 0000 0010 FFFF [0001 0000 001F FFFF] ist die Anzahl der Bytes für 220 das Zeichen. [In eckigen Klammern jeweils die theoretisch maximal möglichen.] 0000 0080 - 110xxxxx 0000 07FF 10xxxxxx 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 128 211 − 27 216 − 211 [221 ] [211 ] [216 ] 1.920 [2.048] 63.488 [65.536] 1.048.576 [2.097.152] Tabelle 2.12.: Die UTF Kodierung im Detail Der Algorithmus lässt theoretisch mehrere Billionen Zeichen zu (27×6 +26×6+1 +25×6+2 +. . .), die aktuelle RFC beschränkt diese jedoch auf die durch UTF-16 erreichbaren, also bis 0010 FFFF (1.114.111). Das erste Byte eines UTF-8-kodierten Zeichens nennt man dabei Start-Byte, weitere Bytes nennt man Folgebytes. Startbytes beginnen also mit der Bitfolge 11 oder einem 0-Bit, während Folgebytes immer mit der Bitfolge 10 beginnen. Betrachtet man die Bitfolgen etwas genauer, erkennt man die große Sinnfälligkeit von UTF-8: Ist das höchste Bit des ersten Byte 0, handelt es sich um ein gewöhnliches ASCII-Zeichen, da ASCII eine 7-Bit-Kodierung ist und die ersten 128 Zeichen des Unicode die ASCII-Zeichen sind. Damit sind alle ASCII-Dokumente automatisch aufwärtskompatibel zu UTF-8. Ist das höchste Bit des ersten Byte 1, handelt es sich um ein Mehrbytezeichen, also ein Unicode-Zeichen mit einer Zeichennummer größer als 127. Sind die höchsten beiden Bits des ersten Byte 11, handelt es sich um das Start-Byte eines Mehrbytezeichens, sind sie 10, um ein Folge-Byte. Die lexikalische Ordnung nach Byte-Werten entspricht der lexikalischen Ordnung nach Buchstaben-Nummern, da größere Zeichennummern mit entsprechend mehr 1-Bits am Anfang kodiert werden. Bei den Start-Bytes von Mehrbyte-Zeichen gibt die Anzahl der 1-Bits vor dem ersten 0-Bit die gesamte Bytezahl des als Mehrbyte-Zeichen kodierten Unicode-Zeichens an. Anders interpretiert, die Anzahl der 1-Bits vor dem ersten 0-Bit nach dem ersten Bit entspricht der Anzahl an Folgebytes, z.B. 1110xxxx 10xxxxxx 10xxxxxx 3 Bits vor dem ersten 0-Bit = 3 Bytes insgesamt, 2 Bits vor dem ersten 0-Bit nach dem ersten 1-Bit = 2 46 2. Die Programmiersprache Perl Folgebytes. Start-Bytes (0xxx xxxx oder 11xx xxxx) und Folge-Bytes (10xx xxxx) lassen sich eindeutig voneinander unterscheiden. Somit kann ein Byte-Strom auch in der Mitte gelesen werden, ohne dass es Probleme mit der Dekodierung gibt, was insbesondere bei der Wiederherstellung defekter Daten wichtig ist. Bytes, die mit 10 beginnen, werden einfach übersprungen, bis ein Byte gefunden wird, das mit 0 oder 11 beginnt. Könnten Start-Bytes und Folge-Bytes nicht eindeutig voneinander unterschieden werden, wäre das Lesen eines UTF-8-Datenstroms, dessen Beginn unbekannt ist, unter Umständen nicht möglich. Zu beachten: Das gleiche Zeichen kann theoretisch auf verschiedene Weise kodiert werden. Jedoch ist nur die jeweils kürzeste mögliche Kodierung erlaubt. Bei mehreren Bytes für ein Zeichen werden die Bits rechtsbündig angeordnet - das rechte Bit des Unicode Zeichens steht also immer im rechten Bit des letzten UTF-8 Bytes. Ursprünglich gab es auch Kodierungen mit mehr als 4 Oktetts (bis zu 6), diese sind jedoch ausgeschlossen worden, da es in Unicode keine korrespondierenden Zeichen gibt und ISO 10646 in seinem möglichen Zeichenumfang an Unicode angeglichen wurde. Für alle auf dem Lateinischen Alphabet basierten Schriften, ist UTF-8 die platzsparendste Methode zur Abbildung von Unicode Zeichen. UTF-8, UTF-16 und UTF-32 kodieren alle den vollen Wertebereich von Unicode. 2.13.9. UTF-8 im Internet Im Internet wird immer häufiger die UTF-8 Kodierung verwendet. So unterstützt auch Wikipedia alle denkbaren Sprachen. Möglich macht all das ein Meta-Tag im Kopf der Webseite: < meta http - equiv =" Content - Type " content =" text / html ; charset = utf -8" / > Auch in eMails ist bei einigen Programmen schon die UTF-8 Kodierung voreingestellt. Sie stellt sicher, dass auch Sonderzeichen unterschiedlicher Länder richtig übertragen und dargestellt werden. Siehe auch: UTF-7, UTF-16, UTF-32, Unicode 2.13.10. UTF-8 Mode in Perl Bei den Perl-Releases vor 5.6 wurden alle Strings als Bytesequenzen betrachtet. Seit der Version 5.6 kann ein String aber nun auch Zeichen enthalten, die mehr als ein Byte benötigen. Bei der Verwendung von Unicode muss man sich keine Gedanken mehr darum machen, wie viele Bits oder Bytes die Repräsentation eines Zeichens verlangt. Perl gibt nur vor, dass alle Unicode-Zeichen die gleiche Länge (d.h. die Länge 1) aufweisen, auch wenn ein Zeichen intern durch mehrere Bytes repräsentiert werden kann. Perl repräsentiert Unicode normalerweise in Form von UTF-8, einer Codierung variabler Länge. Perl kann also schon von sich aus mit Unicode und UTF-8 umgehen. Um nun in einem Unicode-fähigen Editor diese Zeichen innerhalb eines literalen Strings direkt als UTF8-Zeichen erscheinen zu lassen, muss man zu Beginn des Programms "use utf8" bzw. "use encoding 'utf8'" deklarieren. Dann sind alphanumerische Unicode-Sonderzeichen in Variablen- und Routinennamen sowie in Strings zulässig. 2.13. Interne Repräsentation von Schriftzeichen 47 Beispiel 2.40: Anwendung von "use utf8" Hat man keinen Editor mit dem Unicodetext verarbeitet werden kann, so gibt es die Möglichkeit, ein bestimmtes Unicodezeichen als ASCII-Zeichenkette anzugeben. Die ASCIIZeichenkette beginnt mit der Zeichenfolge \x, gefolgt von der Hexadezimalnummer des UNICODE Zeichens. Die Nummer muss in geschweiften Klammern eingeschlossen werden. So könnte man anstatt des kyrillischen Buchstabens auch Zeichenfolge \ x {043 B } schreiben. Den in Beispiel 1 genannten Text könnte man auch als Ich bin die kyrillische Variable \ x {043 F } er \ x {043 B }; schreiben. Bei regulären Ausdrücken ist zu beachten, dass der Punkt in der Unicode-Umgebung auf ein Zeichen passt, nicht mehr auf ein Byte. Dasselbe gilt für Zeichenklassen wie \w und \s. Ähnliche Änderungen ergeben sich unter anderem auch für Funktionen wie length(), die erwartungsgemäß nicht mehr Bytes sondern Zeichen verarbeiten. Beispiel 2.41: Vergleich zweier Unicode-Zeichenketten #!/ usr / bin / perl # Vergleich zweier Unicode - Zeichenketten use strict ; use utf8 ; { my $smiley1 = "?"; my $smiley2 = "\ x {263 A }"; # Schreibweise als ASCII - Zeichenfolge } print " $smiley1 \ n "; print " $smiley2 \ n "; if ( $smiley1 eq $smiley2 ) { print " Smileys sind gleich \ n "; } else { print " Smileys sind nicht gleich \ n "; } Ohne use utf8 würden die beiden Smileys nicht als identisch identifiziert werden. Berücksichtigung spezifischer internationaler Eigenheiten von Buchstaben: In verschiedenen Sprachkulturen können sich die Eigenschaften von Buchstaben unterscheiden, manche Buchstaben gibt es nur in einzelnen Sprachen. Im Englischen gibt es z.B. keine Umlaute. Damit die Eigenschaften von Buchstaben entsprechend ihrer Sprachkultur in einem Programm berücksichtigt werden, müssen in Perl Programmen die sogenannten locale – Einstellungen aktiviert werden. Standardmäßig werden die locale-Einstellungen von Perl ignoriert. Die Aktivierung der sprachspezifischen Eigenschaften von Buchstaben wird mit der Deklaration use locale realisiert und betrifft folgende Operationen und Funktionen im Programm: 48 2. Die Programmiersprache Perl • die Vergleichsoperatoren (lt, le, cmp, ge, gt) sowie die POSIX-Zeichenklassen (z. B. [:alnum:] oder [:alpha:]). • indirekt die Funktion sort, da sie den Vergleichsoperator cmp verwendet • reguläre Ausdrücke und String-modifizierende Funktionen wie uc(), lc() • formatierende Funktionen wie printf() oder write() Das folgende Beispiel zeigt, wie Wörter in Perl von der Routine sort alphabetisch sortiert werden können. Je nachdem welche nationale locale-Einstellung vorgenommen wird, werden die Umlaute unterschiedlich in das Alphabet einsortiert. Ohne Verwendung der Anweisung use locale wird die Standardcodierung ASCII verwendet. Der Aufruf der Anweisung use locale stellt das Programm ab dieser Stelle auf die selbe Kodierung wie die Konsole, von der das Perl Programm aufgerufen wurde. • standard locale (ASCII Codierung): Die Umlaute kommen nach dem Buchstaben Z • deutsches locale: Die Umlaute werden entsprechend Ihrem ae, ue bzw. oe einsortiert. Beispiel 2.42: Auswirkungen von use locale auf sort #!/ usr / bin / perl # Demonstration der Auswirkung von use locale auf sort use strict ; my ( @woerter , @ascii_sortiert , @deu_sortiert ); { @woerter = qw ( der älteste amerikaner öffnete zehn mal den ofen ); # qw bedeutet : Quote Words und erzeugt die Liste : # @woerter = # (" der " , älteste " ," amerikaner " ," öffnete " ," zehn " ," mal " ," den " ," ofen "); @ascii_sortiert = sort @woerter ; # Standardcodierung ASCII print " ASCII : " , join ( ' , ', @ascii_sortiert ) ,"\ n "; { } } use locale ; # Codierung auf die Kodierung der Console setzen @deu_sortiert = sort @woerter ; print " Deutsches Locale : " , join ( ' , ', @deu_sortiert ) ,"\ n "; Ergebnis : ASCII : amerikaner , den , der , mal , ofen , zehn , älteste , öffnete Deutsches Locale : älteste , amerikaner , den , der , mal , öffnete , ofen , zehn 2.14. Lesen der Daten vom Terminal mit utf8 Kodierung Wie im vorherigen Kapitel erwähnt, werden in Perl Zeichen, die nicht zu den ASCII Zeichen gehören, nur dann richtig eingelesen bzw. ausgegeben, wenn das Perl – Programm auf die Kodierung des Konsolenterminals eingestellt ist, von dem das Perl Programm gestartet wurde. Da die Standardkodierung eines LINUX Konsolenterminals auf utf-8 eingestellt ist, muss das Perl Programm die internen Standardkanäle der Eingabe (<STDIN>) und Ausgabe (<STDOUT>) ebenfalls auf utf-8 setzen. Der Programmierer hat dafür zwei Möglichkeiten. 2.14. Lesen der Daten vom Terminal mit utf8 Kodierung 49 2.14.1. Standardein- und ausgabe beim Programmstart auf utf8 festlegen Der Programmierer kann beim Programmstart explizit festlegen, dass die Standardkanäle und <STDOUT> den UNICODE Zeichensatz und die UTF-8 Codierung produzieren, bzw. erwarten. Er muss beim Start des Perl Programms das Perl Kommando mit der Option -C aufrufen. <STDIN> Beispiel 2.43: Setzen von STDIN und STDOUT auf utf-8 beim Programmstart Start des Programms: perl -C my_utf8 . perl Das Programm dazu: #!/ usr / bin / perl # Setzen von STDIN und STDOUT auf utf -8 beim Programmstart use strict ; { my $line ; } while ( $line = < >) { chomp ( $line ); if ( $line =~ /[ äüö ]/) { # siehe Kapitel Reguläre Ausdrücke print " Umlaut gefunden $line \ n "; } } 2.14.2. Standardein- und ausgabe zur Laufzeit auf utf8 festlegen Möchte der Programmierer nicht beim Progammstart festlegen, dass die Standardkanäle und <STDOUT> den UNICODE Zeichensatz und die UTF-8 Codierung produzieren, bzw. erwarten, dann kann er dies auch innerhalb des Programms, also zur Laufzeit des Programms erreichen. Dazu gibt es die spezielle Perl-Routine binmode, die im Programm aufgerufen wird: Perl-Routine : <STDIN> binmode ( Kanal , Kodierung ) Dazu das Programm: #!/ usr / bin / perl -w # Setzen von STDIN STDOUT und STDERR im Programm use strict ; { binmode ( STDIN ,": utf8 "); binmode ( STDOUT ,": utf8 "); binmode ( STDERR ,": utf8 "); my $line ; } while ( $line = < >) { print $line ; } Die Perl Funktion binmode schaltet die im ersten Argument aufgelisteten Kanäle (hier STDIN, STDOUT und STDERR) auf utf8 um. Start des Programms: perl my_utf8_im_programm . perl 50 2. Die Programmiersprache Perl 2.14.3. Lesen aus Dateien mit utf-8 Kodierung Um mit Perl UTF-8 kodierte Unicode Dateien zu lesen gibt es zwei Möglichkeiten: Entweder werden alle open Befehle mit use open ":utf8" auf utf8 gesetzt oder die open Anweisung wird mit drei Argumenten aufgerufen: open ( filehandle , Öffnungsmodus , Dateiname ) filehandle : Name des Filehandles, Öffnungsmodus: Lesen, Schreiben, Anhängen, inklusiv uft-8 Markierung Dateiname: der Name der Datei Beispiel 2.44: Alle Dateien sind utf-8 Dateien. Open Befehl mit 2 Argumenten #!/ usr / bin / perl -w # file :/ DieSprache / useOpen2 . perl # Setzen von STDOUT und STDIN auf utf -8 use strict ; use utf8 ; # Erlaubt Umlaute in Variablennamen use locale ; # Sortiert nach Deutschen Regeln use open ": utf8 "; # Alle Dateien sind utf -8 Dateien { my ( $wort , @woerter , @sorted_woerter ); binmode ( STDIN , ": utf8 " ); # Setzt STDIN auf utf -8 binmode ( STDOUT , ": utf8 " ); # Setzt STDOUT auf utf -8 open ( INP , " abc . txt " ); open ( OUT , " > abc_out . txt " ); open ( OUTSORTED , " > abc_sorted . txt " ); while ( $wort = <INP > ) { chomp ( $wort ); print " $wort \ n "; print OUT " $wort \ n "; push ( @woerter , $wort ); } close INP ; @sorted_woerter = sort @woerter ; print " Sortiert nach deutschen Regeln : \ n " , join ( ', ', @sorted_woerter ) , "\ n "; print OUTSORTED " Sortiert nach deutschen Regeln : \ n " , join ( ', ', @sorted_woerter ) , "\ n "; } close OUT ; close OUTSORTED ; Beispiel 2.45: Dateikodierung wird einzeln definiert. Open Befehl mit 3 Argumenten #!/ usr / bin / perl -w # file :/ DieSprache / useOpen3 . perl # Einlesen und Ausgeben mit utf -8 use strict ; use utf8 ; use locale ; { # Erlaubt Umlaute in Variablennamen # Sortiert nach Deutschen Regeln my ( $wort , @woerter , @sorted_woerter ); binmode ( STDIN ,": utf8 "); binmode ( STDOUT ,": utf8 "); 2.15. Die spezielle Variable : $_ 51 open ( INP ," <: utf8 " ," abc . txt "); # die Datei abc . txt ist eine utf -8 Datei open ( OUT ," >: utf8 " ," abc_out . txt "); # die Datei abc_out . txt ist # eine utf -8 Datei open ( OUTSORTED ," >: utf8 " ," abc_sorted . txt "); } while ( $wort = < INP >) { chomp ( $wort ); print " $wort \ n "; print OUT " $wort \ n "; push ( @woerter , $wort ); } close INP ; @sorted_woerter = sort @woerter ; print " Sortiert nach deutschem Locale : \ n " , join ( ' , ', @sorted_woerter ) ,"\ n "; print OUTSORTED " Sortiert nach deutschen Regeln : \ n " , join ( ' , ', @sorted_woerter ) ,"\ n "; close OUT ; close OUTSORTED ; 2.15. Die spezielle Variable : $_ Die Variable $_ ist eine in Perl intern vordefinierte skalare Variable. Sie gehört zur Gruppe der „Special Variables“ und ist davon die am häufigsten verwendete. Die Variable bekommt bei bestimmten Perl-Anweisungen automatisch einen Wert zugewiesen, bei anderen PerlAnweisungen wird der aktuelle Wert der Variablen verwendet. So speichert z. B. der Einleseoperator den eingelesenen Wert in der Variablen $_, wenn keine explizite Zuweisung zu einer Variablen vor dem Operator steht. Die print Anweisung ohne Variable gibt z. B. den Wert der Variablen $_ aus. Beispiel 2.46: Einlesen und Ausgeben der Standardeingabe anstatt: #!/ usr / bin / perl # Einlesen und Ausgeben mit Diamondoperator use strict ; { my $line ; while ( $line = < >) { print $line ; } } kann man unter impliziter Verwendung der Special Variable $_ auch schreiben: #!/ usr / bin / perl # Einlesen und Ausgeben mit Special Variable use strict ; { while ( < >) { print ; } } Erklärung: Da bei der Einleseoperation <> die Zuweisung an eine Variable fehlt, speichert Perl den Wert der eingelesenen Zeile automatisch in der Special Variable $_. Da nach der print-Anweisung keine Variable folgt, nimmt Perl den Wert, der in $_ gespeichert ist und druckt ihn aus. 52 2. Die Programmiersprache Perl Beispiel 2.47: Spezielle Variable in der foreach-Schleife anstatt: #!/ usr / bin / perl # Demonstration der foreach - Anweisung use strict ; { my $zahl ; foreach $zahl (1..10) { print $zahl ; print "\ n "; } } kann man unter impliziter Verwendung der Special Variable $_ auch schreiben: #!/ usr / bin / perl # foreach - Anweisung mit Special Variable use strict ; { foreach (1..10) { print ; print "\ n "; } } Auch hier fehlt eine Variable um den Wert des Elements bei einem Schleifendurchlauf zu speichern, es wird der Schleifenwert in der Variable $_ gespeichert, bzw. von print ohne Argument ausgegeben. Beispiel 2.48: If-Varianten mit der speziellen Variablen Anstatt der braven Variante: #!/ usr / bin / perl # Demonstration der If - Abfrage use strict ; { while ( $line = < >) { if ( $line =~ / ist /) { print $line ; } } } kann man unter impliziter Verwendung der Special Variable $_ auch schreiben: #!/ usr / bin / perl # If - Abfrage mit Special Variable use strict ; { while ( < >) { if (/ ist /) { print ; } } } 2.16. Datenstrukturen 2: Hashes 53 Noch kürzer geht es mit dem Conditional Statement: #!/ usr / bin / perl # If - Abfrage mit Special Variable und Conditional Statement use strict ; { while ( < >) { print if (/ ist /); } } 2.16. Datenstrukturen 2: Hashes Neben der Möglichkeit Elemente in Listen zu speichern und über Indizes auf sie zuzugreifen, gibt es in Perl die Möglichkeit, Elemente in sogenannten Hashes abzuspeichern. Bei Hashes hat man die Möglichkeit den Schlüssel, mit dem man auf die Elemente zugreift, selbst festzulegen. Die Schlüssel, mit denen man bei Hashes auf die Elemente zugreift, nennt man key, den Wert, der unter einem Key definiert ist, nennt man value. Wenn man einen Hash als Ganzes benutzen möchte, benutzt man das % Zeichen. z.B. %namen, wenn man auf einzelne Elemente zugreifen möchte ähnelt das dem Zugriff auf Array Elemente, nur dass man statt der eckigen Klammern z.B. $werte [5] = 300; geschweifte Klammern verwendet, z.B. $namen {" Meier "} = 4; Bei diesem Beispiel ist "Meier" der key, 4 der value. Somit bilden Hashes eine sehr gute Möglichkeit Wortlisten, die die Häufigkeit von Wörtern in einem Text zählen, zu erzeugen. Beispiel 2.49: Wörter einlesen, in den Hash übertragen (keys) und die Häufigkeit der einzelnen Wörter zählen (values) #!/ usr / bin / perl -w # Erstellen einer Frequenzliste mithilfe von Hash use strict ; { my % lexikon ; my ( $wort , $datei ); print (" Bitte geben Sie den Namen einer Datei ein :\ n "); $datei = < >; open ( DATEI , $datei ); } while ( $wort = < DATEI >) { chomp $wort ; if ( defined $lexikon { $wort }) { $lexikon { $wort }++; } else { $lexikon { $wort } = 1; } } close DATEI ; 54 2. Die Programmiersprache Perl Zugriff und Ausdrucken des Elements, gespeichert unter dem Key "ich": print (" $lexikon { ' ich '}\ n "); (Achtung mit dem Einsatz der Hochkommas!) Erzeugen eines neuen Elements eines Hashes: $lexikon { ' wir '} = 3; Erhöhen des Wertes eines Eintrags in einem Hash, der unter einem bestimmten Key gespeichert ist: $lexikon { ' wir '} = $lexikon { ' wir '} + 1; oder $lexikon { ' wir '}++; 2.16.1. Hash Operatoren es gilt %lexikon , siehe oben. 2.16.2. Löschen von Einträgen im Hash mit Hilfe von delete: my % lexikon = (" ich " ,3 ," du " ,10 ," er " ,5 ," sie " ,10 ," es " ,20); delete ( $lexikon { ' es '}); ergibt: % lexikon = (" ich " ,3 ," du " ,10 ," er " ,5 ," sie " ,10); 2.16.3. Zugriff auf den Hash 2.16.3.1. Zugriff auf alle Keys im Hash keys – Funktion Die Funktion keys liefert als Ergebnis alle keys eines Hashes als Liste: Beispiel 2.50 @key_lexikon = keys % lexikon ; 2.16.3.2. Zugriff auf alle Werte im Hash values – Funktion Die Funktion values liefert als Ergebnis alle values eines Hashes als Liste: Beispiel 2.51 @values_lexikon = values % lexikon ; Tabelle 2.13 fasst Zugriff auf Elemente und sort Anweisungen für Hashes zusammen Numerisches sortiern nach dem Wert print keys %lexikon; print values %lexikon; print @lexikon{’ich’,’du’,’er’}; print scalar(keys %lexikon); print „Ich bin da! \n“ if exists $lexikon{’er’}; foreach $elem (sort keys %lexikon) { print "$elem is $lexikon{$wort} \n"; } foreach $elem (sort {$lexikon {$a} cmp $lexikon {$b}} keys %lexikon ) { print "$elem is $lexikon{$elem}\n"; } foreach $elem ( sort { $lexikon {$b} cmp $lexikon {$a} } keys %lexikon) { print "$elem is $lexikon{$elem}\n"; } foreach $elem ( sort { $lexikon {$a} <=> $lexikon {$b} } keys %lexikon) { print "$elem is $lexikon{$elem}\n"; } Tabelle 2.13.: Hash: Zugriff und sort Anweisungen umgekehrt alphabetisch sortieren nach dem Wert Alphabetisch sortieren nach dem Wert Alle Keys Alle Werte Ein Teil des Hash Wieviele Elemente? Existiert der Key? Sortieren nach dem Key 2.16. Datenstrukturen 2: Hashes 55 56 2. Die Programmiersprache Perl Interaktives Abfragen eines Hashes: print " Eingabe Abkuerzung :"; chomp ( $abk = < STDIN >); print " $abkuerzungen { $abk } = $abk \ n " if defined $abkuerzungen { $abk }; Beispiel 2.52: Einlesen und Sortieren von Werten eines Hashes #!/ usr / bin / perl -w # file :/ DieSprache / hashSort . perl # Beispiel zum Einlesen von Werten eines Hashes und # zum Sortieren eines Hashes use strict ; use utf8 ; { my ( $wort , $elem ); my % wortliste ; while ( $wort = <> ) { chomp $wort ; if ( defined $wortliste { $wort } ) { $wortliste { $wort }++; } else { $wortliste { $wort } = 1; } } foreach ( keys % wortliste ) { print " Der key $_ kommt $wortliste { $_} Mal vor \ n "; } print "/////////////\ n "; foreach $elem ( reverse sort numeric keys % wortliste ) { print " Der key $elem kommt $wortliste { $elem } Mal vor \ n "; } # hier folgt eine Subroutine , Siehe Kapitel über Subroutinen sub numeric { $wortliste { $a } <= > $wortliste { $b } } } 3. Reguläre Ausdrücke in Perl Zur Suche von Zeichenfolgen innerhalb von Strings haben wir bisher nur den Vergleichsoperator und den Zugriff auf die einzelnen Buchstaben kennen gelernt. In Perl kann man aber mit Hilfe von regulären Ausdrücken beliebige Zeichenfolgen innerhalb eines Strings auffinden. Unter einem regulären Ausdruck verstehen wir eine Folge von Zeichen und Metazeichen, die eine Klasse von Zeichenfolgen beschreiben. Um einen regulären Ausdruck von einem String zu unterscheiden, muss der reguläre Ausdruck von slashes eingeschlossen werden: " abc " / abc / ist ein String ist ein regulärer Ausdruck Um eine Skalare Variable mit einem regulären Ausdruck zu vergleichen gibt es die Binding Operatoren : =~ und !~ 3.1. Buchstaben in einem regulären Ausdruck Jeder Buchstabe in einem regulären Ausdruck stimmt nur mit dem gleichen Buchstaben im Skalar überein. Groß- und Kleinschreibung wird unterschieden. Beispiel 3.1 #!/ usr / bin / perl # Suchen eines Strings mithilfe von RA use strict ; { } my $str ; $str = " Hallo "; if ( $str =~ / Hallo /) { print (" gefunden \ n "); } if ( $str !~ / a /) { print (" kein a gefunden \ n "); } 3.2. Übersicht über Metazeichen Metazeichen sind Symbole, die ein spezielle Bedeutung haben und dazu beitragen, dass flexiblere reguläre Ausdrücke geschaffen werden können, um Varianten eines Strings zu finden. In Perl gibt es folgende Metacharachters: \ | ( [ { ^ $ * ) ] } 57 58 3. Reguläre Ausdrücke in Perl + ? . 3.3. Metazeichen . = Wildcard Dieses Metazeichen steht stellvertretend für genau ein Zeichen, aus der Menge aller vorkommenden atomaren Zeichen. if ( $str =~ / H . llo /) { print (" gefunden \ n "); } Der regluäre Ausdruck findet alle Zeichenfolgen, die mit H beginnen und mit llo enden. Zwischen H und llo darf ein beliebiger Buchstabe bzw. atomares Zeichen stehen. 3.4. Metazeichen [ ] = Buchstabenbereiche Buchstabenbereiche werden von den Metazeichen „Eckige Klammern“ umschlossen und spezifizieren alle Buchstaben, die an dieser Stelle zugelassen sind. z . B . / Hall [ iao ]/ # Findet die Strings : Hallo , Halli , Halla z . B . / Hallo [a - z ]/ # Findet alle Strings die mit Hallo beginnen # und am Ende einen Kleinbuchstaben haben . z . B . /[ Hh ] allo / # Findet die Strings : Hallo und hallo 3.5. Metazeichen * , + , ? { } = Quantifizierung Diese Metazeichen legen fest, wie oft der vorherige Buchstabe wiederholt wird: * + ? {n , m } {n} Beliebig oft Mindestenes einmal Null oder einmal Mindestens n mal , aber maximal m mal Genau n mal Beispiel 3.2: Reguläre Ausdrücke: Quantifizierung / Hallo */ # Findet den String " Hall " und alle Strings " Hallo " # mit beliebig vielen " o " am Ende / Hallo +/ # Findet alle Strings " Hallo " mit beliebig vielen " o " am Ende / Hallo ?/ # Findet den String " Hall " und " Hallo " / Hall [ oi ]{1 ,3}/ # Findet den String " Hallo " , " Halli " , " Hallio " , #" Hallooo " , " Hallooi " usw . 3.6. Metazeichen ( ) = Zeichengruppierung 59 3.6. Metazeichen ( ) = Zeichengruppierung Sollen Zeichen zusammengefasst und als eine Einheit gesehen werden, müssen sie mit runden Klammern eingeschlossen werden. Beispiel 3.3: Reguläre Ausdrücke: Zeichengruppierung / geh ( en )?/ # Findet geh und gehen / geh ( en )*/ # Findet geh , gehen , gehenen , usw . 3.7. Metazeichen ˆ = Anfang der Zeile Soll ein String am Anfang der Zeile gesucht werden, dann muss am Anfang des regulären Ausdrucks ein ˆ stehen. Beispiel 3.4: Reguläre Ausdrücke: Anfang der Zeile /^ Toni / # Findet den Namen Toni am Anfang einer Zeile 3.8. Metazeichen $ = Ende der Zeile Soll ein String eine Zeile abschließen, dann muss am Ende des regulären Ausdrucks ein $ stehen. Beispiel 3.5: Reguläre Ausdrücke: Ende der Zeile / Tummi$ / # Findet den Namen Tummi am Ende einer Zeile . 3.9. Metazeichen \= Ausschalten der Metazeichenerkennung Soll in einem String eine Zeichenkette gefunden werden, die einen Metacharacter enthält, dann muss im regulären Ausdruck der gesuchte Metacharacter mit einem Backslash vor der Interpretierung als Metacharacter geschützt werden. Beispiel 3.6: Reguläre Ausdrücke: Ausschalten der Metazeichenerkennung / Toni \+ Sepp / # Findet den Namen Toni + Sepp Beispiel 3.7: Zeilenweises lesen aus der Datei „zeilen.txt“ und mit einem regulären Ausdruck vergleichen #!/ usr / bin / perl # file :/ RegulaereAusdruecke / reg . perl # Suchen einer Zeichenkette beim Einlesen einer Textdatei use strict ; { my $filename = " zeilen . txt "; my $line ; open ( EINGABE , $filename ); while ( $line = < EINGABE > ) { chomp ( $line ); if ( $line =~ /^ Hallo / && $line !~ / Hansi$ / ) { print (" Hallo am Anfang einer Zeile gefunden , die "); print (" nicht mit Hansi endet .\ n "); print (" $line \ n "); 60 3. Reguläre Ausdrücke in Perl } } } 3.10. Metazeichen [ˆ ] = negierte Buchstabenbereiche Negierte Buchstabenbereiche werden von den Metazeichen „Eckige Klammern“ und dem ˆ -Buchstaben als erster Buchstabe nach der öffnenden Klammer definiert. Sie spezifizieren alle Buchstaben, die an dieser Stelle nicht zugelassen sind. Beispiel 3.8: Reguläre Ausdrücke: negierte Buchstabenbereiche / Hall [^ ioa ]/ # Findet die Strings die mit Hall beginnen , # außer Hallo , Halli , Halla / Hallo [^ a - zäüöß ] $ / # Findet alle Strings am Ende der Zeile ( Strings ) die mit # Hallo beginnen und mit keinem Kleinbuchstaben enden . 3.11. Buchstabenklassen ohne UNICODE Ein Ausdruck der Form [[:name:]] findet alle Buchstaben, die zu dieser Buchstabenklasse gehören, z.B. Beispiel 3.9 [[: lower :]] findet alle Kleinbuchstaben Die Buchstabenklassen können in Perl auch mit einer Escape-Sequenz ausgedrückt werden. Die wichtigsten Buchstabenklassen sind: Buchstabenklasse [[:digit:]] [[:lower:]] [[:upper:]] [[:word:]] [[:space:]] [ˆ[:digit:]] [ˆ[:lower:]] [ˆ[:upper:]] [ˆ[:word:]] Escape Sequenz \d \l \u \w \s \D \L \U \W \b Beschreibung Dezimalzahl Kleinbuchstabe Großbuchstabe Wort-Buchstabe Leerzeichen/ Tabs keine Dezimalzahl kein Kleinbuchstabe kein Großbuchstabe kein Wort-Buchstabe Wortgrenze Tabelle 3.1.: Buchstabenklassen ohne UNICODE 3.12. Buchstabenklassen mit UNICODE Wenn das Perl Programm im UNICODE Mode läuft: • Verwendung des Pragmas: use locale; • Starten des Perl Programms mit der Option -C (für UTF-8 Files) • die Standardkodierung der Console (UTF-8) 3.13. Zugriff auf gruppierte Teile des Regulären Ausdrucks 61 dann gilt die Buchstabenklasse \w (Wort-Buchstabe) nicht mehr. Um Buchstabenklassen weiterhin zu verwenden, müssen die Definitionen von UNICODE verwendet werden, siehe Tabelle 3.2. UNICODE führt sogenannte Properties ein, die mit einem \p und den in geschweiften Klammern einschlossenen Eigenschaften notiert werden. Verwendet man als UNICODE Property nicht den Kleinbuchstaben p sondern den Großbuchstaben P, dann spricht UNICODE die Negation der in geschweiften Klammern einschlossenen Eigenschaften an. Es gibt noch eine weitere Möglichkeit eine Eigenschaft zu negieren: Der in geschweifter Klammer definierten Eigenschaft wird das Negationszeichen ^ vorgestellt. Beispiel 3.10 \p{L} \P{L} \ p { Ll } \ P { Ll } \ p {^ Ll } Letter - Buchstabe KEIN Letter - Buchstabe lowercase Buchstabe findet alle Kleinbuchstaben alle Buchstaben , außer die Kleinbuchstaben Negation : kein lowercase Buchstabe : findet alle Zeichen , außer Kleinbuchstaben Die Buchstabenklassen können in Perl auch mit einer UNICODE Property Sequenz ausgedrückt werden. Die wichtigsten Buchstabenklassen und ihre UNICODE Property Sequenzen sind: UNICODE Property Sequenz \p{N} \p{L} \p{Ll} \p{Lu} \p{Z} \P{Lu} \p{ˆLu} Beschreibung Dezimalzahl Buchstabe Kleinbuchstabe Großbuchstabe Trennzeichen Kein Großbuchstabe Kein Großbuchstabe Tabelle 3.2.: Buchstabenklassen mit UNICODE 3.13. Zugriff auf gruppierte Teile des Regulären Ausdrucks Man kann reguläre Ausdrücke mit runden Klammern strukturieren. Dadurch erreicht man erstens eine Gruppierung von Ausdrücken und zweitens einen Zugriff auf Teile des gesamten Treffers (Substrings). Perl nummeriert die Gruppen durch und erlaubt auf diese über die Variablen $1,$2 zuzugreifen. Beispiel 3.11: Zugriff auf gruppierte Teile des Regulären Ausdrucks #!/ usr / bin / perl # file :/ RegulaereAusdruecke / wortGruppe . perl # Extrahiert 3 Wörter aus einem Trigram # Aufruf mit perl -C wortGruppe . perl use strict ; use locale ; # schaltet auf UNICODE Mode , verhindert , dass # \ w auch Umlaute findet { my $line ; while ( $line = <> ) { chomp ( $line ); 62 3. Reguläre Ausdrücke in Perl } } } if ( $line =~ /^(\ w +)\ s +(\ w +)\ s +(\ w +) $ / ) { print (" Backslash w Search : Trigram gefunden : $1 .. $2 .. $3 \ n "); if ( $line =~ /^(\ p { L }+)\ s +(\ p { L }+)\ s +(\ p { L }+) $ / ) { print (" UNICODE p { L } Search : Trigram gefunden : $1 .. $2 .. $3 \ n "); } Findet alle Zeilen mit 3 Wörtern und gibt bei der Zeile: Das ist gut folgendes aus: Das .. ist .. gut 3.14. Globales Suchen in einer Zeile Standardmäßig sucht Perl, genauso wie der UNIX-Befehl grep, nur nach dem ersten Vorkommen einer Zeichenkette innerhalb eines String. Kommt eine Zeichenkette mehrmals in einem String vor, dann übersieht Perl die nachfolgenden Zeichenketten, da die Suchposition immer am Anfang der Zeile bleibt. Dieses Verhalten kann dadurch geändert werden, dass die Suche nach dem regulären Ausdruck auf „global-Search“ gesetzt wird. Dazu muss dem regulären Ausdruck ein /g nachgestellt werden. Findet Perl in einer Zeile die gesuchte Zeichenkette, dann setzt Perl in der Zeile hinter der gefundenen Zeichenkette die Suche fort. Beispiel 3.12 #!/ usr / bin / perl # Beispiel für Globales Suchen use strict ; { my ( $line ); print " Eingabe > > >"; chomp ( $line = < >); while ( $line =~ /\ s *(\ w +)\ s */ g ) { print (" found : $1 \ n "); } } > perl global . perl Eingabe : ich du er sie found : ich found : du found : er found : sie 3.15. Ersetzen von Strings: substitute 63 3.15. Ersetzen von Strings: substitute In Perl können Zeichenketten von anderen Zeichenketten ersetzt werden. Dazu gibt es den substitute Befehl. Mit Hilfe eines Regulären Ausdrucks kann spezifiziert werden, was ersetzt werden soll. • Ersetzt in der Zeile $line das erste Auftreten der Zeichenkette „von“ durch „nach“ $line =~ s / von / nach /; • Ersetzt caseinsensitiv in der Zeile $line das erste Auftreten der Zeichenkette „von“ durch „nach“. Es werden alle Groß-/Kleinschreibungskombinationen von „von“ akzeptiert. $line =~ s / von / nach / i ; • Ersetzt in der Zeile $line jedes Auftretens der Zeichenkette „von“ durch „nach“ $line =~ s / von / nach / g ; • Ersetzt in der Zeile $line alle vierstelligen Zahlen durch den String „nnnn“ $line =~ s /\ d \ d \ d \ d / nnnn / g ; • oder $line =~ s /\ d {4}/ nnnn / g ; 3.16. Greedy-Nongreedy Verhalten bei Quantifizierung Bei den * und + Quantifizierungen von Zeichen stellt sich die Frage, wie viele Zeichen Perl in einem Pattern matched. Per Default versucht Perl so viele Zeichen zu matchen wie möglich. Dieses Verhalten nennt man „Greedy-Matching“: Beispiel 3.13: Greedy Verhalten bei Quantifizierung $wort = " Schifffahrt "; $wort =~ s / f +/ x /; print " greedy matching : $wort \ n "; Perl matched alle drei f in Schifffahrt und ersetzt sie durch ein x: greedy matching : Schixahrt Das Greedy-Matching wird unterbunden, wenn dem Quantifizierer ein Fragezeichen nachgestellt wird: Beispiel 3.14: Nongreedy Verhalten bei Quantifizierung $wort = " Schifffahrt "; $wort =~ s / f +?/ y /; print " NON greedy matching : $wort \ n "; Perl ist auf NON Greedy gesetzt und matched nur das erste f in Schifffahrt und ersetzt es durch ein y: NON greedy matching : Schiyffahrt Beispiel 3.15: Nongreedy Verhalten mit Global Option bei Quantifizierung $wort = " Schifffahrt "; $wort =~ s / f +?/ y / g ; print " NON greedy GLOBAL matching : $wort \ n "; 64 3. Reguläre Ausdrücke in Perl Perl ist zwar auf NON Greedy gesetzt, aber die Option global matched jedes einzelne f in Schifffahrt und ersetzt jedes einzelne durch ein y NON greedy GLOBAL matching : Schiyyyahrt 3.17. Zugriff auf gruppierte Teile des regulären Ausdrucks beim Ersetzen von Zeichenketten Wie vorher erwähnt, kann man reguläre Ausdrücke mit runden Klammern strukturieren. Dadurch kann man beim Ersetzen von Zeichenketten auf die gefundenen Gruppen zugreifen. Perl nummeriert die Gruppen durch und erlaubt auf diese über die Variablen \1, \2 zuzugreifen. Beispiel 3.16: Zugriff auf gruppierte Teile des regulären Ausdrucks beim Ersetzen von Zeichenketten $zeile =" Ja Nicht "; $zeile =~ s /^(\ w +) (\ w +) $ / $2 $1 /; print (" $zeile \ n "); Dreht in allen Zeilen mit 2 Wörtern die Reihenfolge der Wörter um. Ja Nicht ergibt folgendes: Nicht Ja 3.18. Suchen über Zeilengrenzen hinweg Manche zu suchenenden Ausdrücke lassen sich schlecht innerhalb einer Zeile finden. Hier kann es sinnvoll sein, über Zeilengrenzen hinweg zu suchen. Der Input Record Separator $/ entscheidet, an welchem Zeichen der Input endet. Voreingestellt ist der Input Record Separator auf das Newline-Zeichen. Daher kann man den Input zeilenweise lesen, wenn man while ($input = <>) {... schreibt. Um den Input Record Separator auf ein anderes Zeichen zu setzen kann man diesen einfach zuweisen, zum Beispiel auf ein Space. $/ = " "; Um über Zeilengrenzen hinweg zu suchen macht es Sinn den Input Record Separator komplett auszuschalten. undef $/; Innerhalb des regulären Ausdrucks, der über die Zeilengrenzen hinweg gesucht werden soll, gibt es weitere Punkte zu beachten: • Um den Dot Operator . über Zeilengrenzen hinweg verwenden zu können, muss die Option /s eingeschaltet werden. • Um ^ und $, also Zeilenanfang und -Ende, weiterhin nutzen zu können, muss die Option /m eingeschaltet werden. 3.18. Suchen über Zeilengrenzen hinweg Beispiel 3.17: Suchen über Zeilengrenzen hinweg #!/ usr / bin / perl # Suchen über Zeilengrenzen hinweg use strict ; use utf8 ; use locale ; { my $input ; open ( TEXT ," <: utf8 " ," sz_artikel . txt ") or die " file not found !"; undef $ /; # Input Record Separator wird ausgeschaltet $input = < TEXT >; # $input enthält den kompletten Text # findet zwei großgeschriebene Wörter nacheinander while ( $input =~ / (\ p { Lu }\ p { Ll }+\ s \ p { Lu }\ p { Ll }+)/ g ) { print $1 ,"\ n "; } # findet Wortfolgen die mit Punktuationszeichen enden while ( $input =~ /(\ p { Lu }.+?\ p { P })/ gs ) { print $1 ,"\ n "; } # findet Zeilen die mit Punktuationszeichen enden while ( $input =~ /^(\ p { Lu }.+?\ p { P }) $ / gm ) { print $1 ,"\ n "; } } close TEXT ; 65 4. Systemroutinen in Perl 4.1. Vorbemerkung Perl stellt eine Vielzahl von fertigen Routinen zur Verfügung. Die folgende Auswahl stellt daher nur einen sehr geringen Teil der in Version Perl 6 vorhandenen Routinen vor. Prinzipiell werden Systemroutinen mit ihrem Namen, dem system subroutine identifier, aufgerufen. Nach dem Namen werden geklammert Argumente an die Systemroutine übergeben. Systemroutinen geben nach ihrer Ausführung einen Wert an den aufrufenden Programmteil zurück, der mit einer Zuweisung auf eine Variable geschrieben werden kann. Formatierungskonvention: • Die Argumente von Systemroutinen können entweder in Klammern eingeschlossen werden oder als eine mit Komma getrennte Folge von Einzelargumenten übergeben werden: • Stehen die Argumente in Klammern, dann steht zwischen dem Routinennamen in der öffnenden Klammer kein Space • Werden die Argumente als Reihung aufgelistet, dann steht zwischen dem Routinennamen und den Agumenten ein Leerzeichen. Beispiel 4.1 print (" Wort "); print " Wort "; 4.2. split Aufruf : < list variable > = split (/ < pattern >/ , < string > | < skalar variable >); Die Routine split teilt eine Zeichenkette in Einheiten, die auf eine list variable geschrieben werden können. Die Zeichenkette wird der Routine entweder direkt als String oder als skalare Variable übergeben. Die Aufteilung des Strings erfolgt nach dem in pattern angegebenen Trennzeichen (auch mehrere Zeichen sind möglich). Wird kein Trennzeichen angegeben, so wird nach whitespace(Leerzeichen, Tab, Newline) getrennt. Soll nach einzelnen Buchstaben getrennt werden, so gibt man als pattern den leeren String, dargestellt durch // an. Die angegebenen Trennzeichen werden nicht mit zurückgegeben, bei der Zuweisung auf ein Array gehen die Trennzeichen also verloren. Beispiel 4.2: Einen Satz in Wörter zerlegen $satz = " Das ist ein Satz "; @woerter = split (/ / , $satz ); Ergebnis : $woerter [0] == Das $woerter [1] == ist 66 4.3. ord 67 $woerter [2] == ein $woerter [3] == Satz Beispiel 4.3: Ein Wort in Buchstaben zerlegen $wort = " Wort "; @buchstaben = split (// , $wort ); Ergebnis : $buchstaben $buchstaben $buchstaben $buchstaben [0] [1] [2] [3] == == == == W o r t Beispiel 4.4: Einen Text in Wörter zerlegen Einen Text in Wörter zerlegen. Das heißt, nicht nur an Leerzeichen trennen, sondern auch an .,;: #!/ usr / bin / perl # Zerlegen eines Texts in Wörter use strict ; { my ( $text , $zeile ); my ( @woerter ); my % anzahl ; $text = " info . txt "; open ( INFO , $text ); } while ( $zeile = < INFO >) { chomp $zeile ; @woerter = split (/[ ,. ;:]+/ , $zeile ); # ohne '+ ' ist das haeufigste Wort " " foreach my $wort ( @woerter ) { $anzahl { $wort }++; } } close INFO ; 4.3. ord Aufruf : < skalar variable > = ord ( < char >| < skalar variable >) Die Routine ord gibt den dezimalen ASCII Wert des ersten übergebenen Zeichens zurück. Dieser Wert kann über eine Zuweisung auf eine skalare Variable geschrieben werden. Das Argument von ord darf sowohl ein String sein, als auch eine skalare Variable, die einen String enthält. Beispiel 4.5: Ermitteln des ASCII Wertes von einem Buchstaben $buchstabe = " u "; $ascii_von_u = ord ( $buchstabe ); Ergebnis : $ascii_von_u == 117 68 4. Systemroutinen in Perl 4.4. chr Aufruf : < skalar variable > = chr ( < number >| < skalar variable >) Die Routine chr gibt das ASCII Zeichen zurück, das unter dem übergebenen Wert kodiert ist. Dieser Wert kann über eine Zuweisung auf eine skalare Variable geschrieben werden. Das Argument von char darf sowohl eine Dezimalzahl sein, als auch eine skalare Variable, deren r-value eine Zahl ist. Beispiel 4.6: Ermitteln des unter 117 kodierten Zeichens $ascii_zahl = 117; $ascii_zeichen_117 = chr ( $ascii_zahl ); Ergebnis : $ascii_zeichen_117 == u 4.5. length Aufruf : < skalar variable > = length ( < string >| < skalar variable >) Die Routine length gibt die Anzahl der Zeichen zurück, die das Argument enthält. Dieser Wert kann über eine Zuweisung auf eine skalare Variable geschrieben werden. Argument von length darf sowohl ein string sein, als auch eine skalare Variable, deren r-value ein string ist. Beispiel 4.7: Ermitteln der Länge eines Strings $wort = " Wort "; $laenge = length ( $wort ); print (" Das Wort hat $laenge Buchstaben "); Ausgedruckt wird : Das Wort hat 4 Buchstaben 4.6. scalar Aufruf : < skalar variable > = scalar ( < list variable >) zwingt ein Array in einen skalaren Kontext. Die einzige Information, die dann übrig bleibt, ist die Anzahl der Elemente. Diesen Wert liefert die Funktion an die aufrufende Stelle zurück. Es ist also möglich die Information sofort einer skalaren Variablen mit dem Zuweisungsoperator „=“ zuzuweisen. Auf keinen Fall kann die Länge eines Arrays mit der Funktion length bestimmt werden. Diese dient dazu die Länge eines Skalars zu bestimmen. Lediglich bei der Buchstabenzerlegung eines Strings hatten wir die Arraylänge des Buchstabenarrays indirekt mithilfe von scalar bestimmt. Warum: Das Buchstabenarray muss ja gerade soviel Elemente haben wie der String Buchstaben. Beispiel 4.8: Ermitteln der Anzahl der Elemente in einer Liste @worte = (" Heute " ," regnet " ," es "); $laenge = scalar ( @worte ); print (" Die Liste Worte hat $laenge Listenelemente "); 4.7. join 69 Ausgedruckt wird : Die Liste Worte hat 3 Listenelemente 4.7. join Aufruf : < skalar variable > = join ( < string > , < list variable >) Die Routine join fügt alle Elemente aus der list variable zu einer Zeichenkette zusammen. Die einzelnen Elemente der list variable werden dabei durch die im ersten Argument von join angegebene Zeichenkette getrennt. Wird der leere String als Trenner angegeben, so werden alle Elemente der list variable zusammengeschrieben. Der von join zurückgegebene String kann über eine Zuweisung auf eine skalare Variable geschrieben werden. Beispiel 4.9: Ein als array gespeichertes Wort in einen string schreiben @wort_in_buchstaben ; $wort_in_buchstaben [0] $wort_in_buchstaben [1] $wort_in_buchstaben [2] $wort_in_buchstaben [3] = = = = " W "; " o "; " r "; " t "; $wort_als_string = join ("" , @wort_in_buchstaben ); $buchstaben_als_string = join (" " , @wort_in_buchstaben ); print (" $wort_als_string $buchstaben_als_string "); Ausgedruckt wird : Wort W o r t 4.8. pop Aufruf : < variable > = pop ( < array variable >) Die Routine pop entfernt das letzte Element aus der array variable und liefert es als Ergebnis zurück. Über eine Zuweisung kann das entfernte Element auf eine Variable geschrieben werden. Das Array wird um 1 gekürzt. Beispiel 4.10: Das letzte Element in einem Array entfernen @liste ; $liste [0] $liste [1] $liste [2] $liste [3] = = = = " eins "; " zwei "; " drei "; " vier "; $letztes = pop ( @liste ); print (" Das letzte Element in der Liste war $letztes "); Ausgedruckt wird : Das letzte Element in der Liste war vier 70 4. Systemroutinen in Perl 4.9. push Aufruf : push ( < array variable > , < skalar variable >) Die Routine push hängt das in skalar variable angegebene Element an die array variable an. Die array variable wird also als Stapel betrachtet. Das letzte Element ist immer zuoberst. Das array wird um 1 verlängert. Beispiel 4.11: Ein neues Element ans Ende eines Arrays stellen @liste ; $liste [0] $liste [1] $liste [2] $liste [3] = = = = " eins "; " zwei "; " drei "; " vier "; $neues = " fünf "; push ( @liste , $neues ); print (" Das letzte Element in der Liste ist jetzt $liste [4]"); Ausgedruckt wird : Das letzte Element in der Liste ist jetzt fünf ; 4.10. shift Aufruf : < variable > = shift ( < array variable >) Die Routine shift entfernt das erste Element aus der array variable und liefert es als Ergebnis zurück. Alle Elemente in array variable rücken im Index um 1 nach vorne. Über eine Zuweisung kann das entfernte Element auf eine Variable geschrieben werden. Beispiel 4.12: Das erste Element in einem Array entfernen @liste ; $liste [0] $liste [1] $liste [2] $liste [3] = = = = " eins "; " zwei "; " drei "; " vier "; $erstes = shift ( @liste ); print (" Das erste Element in der Liste war $erstes \ n "); print (" Das neue erste Element in der Liste ist $liste [0]"); Ausgedruckt wird : Das erste Element in der Liste war eins Das neue erste Element in der Liste ist zwei 4.11. unshift 71 4.11. unshift Aufruf : unshift ( < array variable > , < variable >) Die Routine unshift fügt vor das erste Element aus <array variable> das Element <variable> ein. Alle Elemente in <array variable> rücken im Index um 1 nach hinten. Beispiel 4.13: Ein neues Element an den Anfang eines Arrays stellen @liste ; $erstes =" null "; $liste [0] = " eins "; $liste [1] = " zwei "; $liste [2] = " drei "; $liste [3] = " vier "; unshift ( @liste , $erstes ); print (" Das erste Element in der Liste soll sein : $erstes \ n "); print (" Das neue erste Element in der Liste ist $liste [0]"); Ausgedruckt wird : Das erste Element in der Liste soll sein : null Das neue erste Element in der Liste ist null 4.12. reverse Aufruf : < variable > = reverse ( < variable >) Die Routine reverse liefert im Array Kontext alle Elemente in umgekehrter Reihenfolge. In einem skalaren Kontext liefert reverse die Zeichen des Skalars in umgekehrter Reihenfolge. Über eine Zuweisung können Arrayelemente bzw. Zeichen auf ein Array bzw. einen Skalar geschrieben werden. Beispiel 4.14: Die Elemente in einem Array umdrehen @liste ; @liste_umgedreht ; $liste [0] = " eins "; $liste [1] = " zwei "; $liste [2] = " drei "; $liste [3] = " vier "; @liste_umgedreht = reverse ( @liste ); print (" @liste \ n "); print (" @liste_umgedreht "); Ausgedruckt wird : eins zwei drei vier vier drei zwei eins 72 4. Systemroutinen in Perl Beispiel 4.15: Palindrom Ist ein Wort ein Palindrom? my $wort = " reliefpfeiler "; if ( $wort eq reverse ( $wort )){ print (" $wort ist ein Palindrom "); } else { print (" $wort ist kein Palindrom "); } Ausgedruckt wird : reliefpfeiler ist ein Palindrom 4.13. sort Aufruf : < list variable > = sort ( < list variable >) Die Routine sort gibt die Elemente der list variable in aufsteigender Reihenfolge, entsprechend den normalen Konventionen des Zeichenvergleichs, zurück. Über eine Zuweisung können die Elemente auf ein Array geschrieben werden. Beispiel 4.16: Die Elemente in einem Array sortieren my @woerter ; my @woerterbuch ; $woerter [0] = haus ; $woerter [1] = aal ; $woerter [2] = computer ; $woerter [3] = compiler ; @woerterbuch = sort ( @woerter ); print (" @woerterbuch "); Ausgedruckt wird : aal compiler computer haus Implementierung von sort Alphabetisch sortiert: foreach my $wort ( sort keys % worthash ) { print " $wort \ n "; } Nach Häufigkeit sortiert: foreach my $wort ( sort { $worthash { $b } <= > $worthash { $a } } keys % worthash ) { print " $wort = $worthash { $wort }\ n "; } 5. Subroutinen in Perl Vorbemerkung Um große Programmieraufgaben übersichtlich und strukturiert zu realisieren, ist es sehr empfehlenswert, Teilaufgaben des Programms in eigenen Programmteilen, sogenannten Unterprogrammen, realisieren zu lassen. Unterprogramme können selbstständig entwickelt, getestet, optimiert, von Fehlern befreit und in anderen Programmen wiederverwendet werden. Die Unterprogrammtechnik ist auch das zentrale Konzept bei der modularen Programmierung: Größere Unteraufgaben werden in eigenen Modulen erledigt. Eine Programmiersprache, die die Unterprogrammtechnik unterstützt muss in der Lage sein, Programmteile zusammenzufassen, diesen Programmteilen einen Namen zu geben und ihnen Werte zu übergeben, bzw. innerhalb dieser Programmteile Werte ermitteln zu lassen, die im aufrufenden Programm zur Verfügung stehen. Perl unterstützt die Unterprogrammtechnik, Programmteile können in Unterprogrammen, genannt Subroutinen, zusammengefasst werden. Subroutinen können Werte übergeben werden, die Werte können in Subroutinen weiterverarbeitet werden und sie können dem aufrufenden Programm zurückgegeben werden. Das Unterprogramm kann somit eine eigene Aufgabe realisieren und mit dem aufrufenden Programm zusammenarbeiten. Ein Beispiel für Subroutinen in Perl ist z.B. die Funktion print zum Ausgeben von Text. print (" Hallo "); Der Subroutine print wird das Argument "Hallo" übergeben: Im Unterprogramm print wiederum werden alle notwendigen Systemroutinen aufgerufen, die auf dem Bildschirm genau an der richtigen Stelle den Text "Hallo" ausgeben. 5.1. Definition von Subroutinen in Perl In Perl besteht eine Subroutine aus einem • Subroutinenkopf und einem • Subroutinenrumpf. Im Subroutinenkopf wird der Name der Subroutine festgelegt. In Perl steht es dem Benutzer frei, hinter dem Subroutinennamen in runden Klammer eingeschlossen die Parametertypen der Subroutine aufzulisten. Einen Subroutinenkopf mit Deklaration der Typen der Parameter nennt man in Perl Subroutinen-Prototypen. Die Parameter, mit denen eine Subroutine aufgerufen wird, stellen die Schnittstelle zwischen aufrufendem Programm und Unterprogramm dar. Der Subroutinenrumpf beginnt hinter dem Subroutinenkopf und wird mit geschweiften Klammern umschlossen. Er besteht aus • Parametersektion und • Anweisungsblock. 73 74 5. Subroutinen in Perl In der Parametersektion werden die Variablen deklariert, die innerhalb der Subroutine verwendet werden. Ausserdem werden hier die Parameterwerte, mit denen eventuell die Subroutine aufgerufen wird, den Subroutinenvariablen zur Weiterverarbeitung übergeben. Im Anweisungsblock stehen alle Anweisungen, die ausgeführt werden, wenn die Subroutine abgearbeitet wird. Eine Subroutine wird mit ihrem Namen und eventuellen Argumenten aufgerufen. Da die Programmiersprache Perl nicht überprüft, ob die Anzahl und der Typ der Argumente, mit denen eine Subroutine definiert ist und aufgerufen wird, übereinstimmt, muss der Programmierer unbedingt selbst darauf achten, dass es hier keine Widersprüche gibt. 5.2. Datenaustausch zwischen Subroutinen und Hautpprogramm Subroutinen können mit oder ohne Argumenten aufgerufen werden, der Praefix & vor dem Subroutinennamen kann weggelassen werden. ACHTUNG: Perl überprüft nicht, ob die Anzahl und Art der Argumente, mit denen eine Subroutine aufgerufen wird, mit der Definition der Subroutine übereinstimmt. Den Datenaustausch zwischen dem aufrufenden Programm und einer Subroutine kann über drei Arten realisiert werden: • Datenaustausch über Argumente: Die Subroutine wird mit beliebigen Argumenten, sogenannten Argumentvariablen aufgerufen. Die Werte der Argumentvariablen können sowohl gelesen, als auch verändert werden. Der Programmierer entscheidet, ob eine Subroutine den Wert der Argumentvariablen, den sie im Hauptogramm besitzt, innerhalb der Subroutine ändert, oder ob die Subroutine den Wert der Argumentvariablen nur liest. my $wert =1; # Aufruf einer Subroutine ohne Argument : & clear_screen (); # Aufruf einer Subroutine mit Argument : & drucke ( $wert ); • Datenaustausch über einen Rückgabewert der Subroutine: Subroutinen können über ihren Aufruf dem aufrufenden Programm auch Werte zurückgeben (siehe Rückgabewerte von Subroutinen 5.5) my $erg ; # Aufruf der Subroutine mit Rückgabewert : $erg = & aufeins (); # innerhalb der Subroutine : sub aufeins () { ... return 1; } • Datenaustausch über globale Variablen: Die Subroutine greift auf Variablen zu die nicht innerhalb der Subroutine definiert werden. Diese Art von Variablen heißt globale Variable (siehe 5.6). 5.3. Zugriff auf die Argumentvariablen in Subroutinen 75 5.3. Zugriff auf die Argumentvariablen in Subroutinen Werden an eine Subroutine Argumentvariablen übergeben, dann werden direkte Verweise auf die einzelnen Elemente der Argumentvariablen in der speziellen System-Listenvariable @_ (genannt STACK Listenvariable) gespeichert. Die STACK Listenvariable steht mit ihren Werten dem Programmier innerhalb der Subroutine zur Verfügung. Er kann Werte aus dieser Liste lesen und verändern. Das erste Argument ist im 0. Element der Liste @_ gespeichert usw. Beispiel 5.1: Übergabe der Argumente, Speicherung in der STACK Listenvariable @_ my $wert1 =1; my $wert2 =2; my @gerade = (2 ,4 ,6) # Aufruf : & teste ( $wert1 ); # in @_[0] steht der direkte Verweis auf die Variable $wert1 # Aufruf : & testezwei ( $wert1 , $wert2 ); # in @_[0] steht der direkte Verweis auf die Variable $wert1 # in @_[1] steht der direkte Verweis auf die Variable $wert2 # Aufruf : & teste_gerade ( @gerade ); # in @_[0] steht der direkte Verweis auf $gerade [0] # in @_[1] steht der direkte Verweis auf $gerade [1] # in @_[2] steht der direkte Verweis auf $gerade [2] Im folgenden Beispiel wird gezeigt, wie Argumente an eine Subroutine übergeben werden und wie eine Subroutine auf die Argumentvariable zugreifen kann. Beispiel 5.2: Übergabe der Argumente, Speicherung und Zugriff auf die STACK Listenvariable @_ #!/ usr / bin / perl # file : Subroutinen / uebergabe_stack . perl # zeigt die Übergabe an Lokale Variablen { use strict ' vars '; my $wert1 =1; my $wert2 =2; } & drucke ( $wert1 ); & druckezwei ( $wert1 , $wert2 ); sub drucke ( $ ) { print " Argument eins = @_[0]\ n "; } sub druckezwei ( $$ ) { print " Argument eins = @_[0]\ n "; print " Argument zwei = @_[1]\ n "; } 76 5. Subroutinen in Perl Der direkte Zugriff auf Argumentvariablen über die Elemente der speziellen STACK Listenvariablen @_ hat in Perl einen gefährlichen Nebeneffekt: Perl kann über die Arrayelemente von @_ direkt auf die Argumentvariablen im aufrufenden Programm zugreifen. Jede Veränderung eines Listenelements der speziellen STACK Listenvariable @_ ändert den Wert des aufrufenden Arguments: Beispiel 5.3: Übergabe der Argumente an die STACK Listenvariable @_ und Ändern des Wertes #!/ usr / bin / perl # file : Subroutinen / uebergabe_stack_incr . perl # zeigt die Übergabe an Lokale Variablen { use strict ' vars '; my $wert1 =1; } & drucke ( $wert1 ); & pluseins ( $wert1 ); & drucke ( $wert1 ); sub drucke ( $ ) { print " Argument eins = @_[0]\ n "; } sub pluseins ( $ ) { @_[0] = @_[0]+1; } Die Technik in einer Subroutine direkt mit den Elementen der speziellen STACK Listenvariable @_ zu arbeiten ist nicht empfehlenswert. Besser ist es bei lesendem Zugriff den Wert der Argumentvariablen in einer lokalen Variablen der Subroutine zu speichern (siehe: Lokale Variablen 5.3.1). Wenn der Wert einer Argumentvariablen geändert werden soll, dann ist es besser der Subroutine eine Referenz auf die Argumentvariable zu übergeben. Der Programmierer ändert dann über den Umweg der Referenz die Argumentvariable. (siehe: Die Verwendung von Referenzen 5.4.1) 5.3.1. Lokale Variablen Lokale Variablen werden häufig auch als lexikalische Variablen bezeichnet. Sie entsprechen den Ideen modularer Programmierung, d.h. dass man in jedem abgeschlossenen Teil des Programms sicher sein kann, dass kein Wert unerwünschterweise von außerhalb dieses Teils geändert werden kann. Dies erleichtert die Fehlersuche und ist im Übrigen unerlässlich, falls mehrere Teile eines größeren Programms von verschiedenen Personen geschrieben werden sollen. Die Deklaration von lokalen Variablen geschieht mit my. Dabei können auch mehrere Variablen auf einmal deklariert werden, außerdem können sie auch gleich initialisiert werden: my ( $var1 , $var2 ); my @array = (2 ,5 ,7); innerhalb einer Subroutine: sub drucke () { my ( $var1 , $var2 ); ... } 5.3. Zugriff auf die Argumentvariablen in Subroutinen 77 5.3.2. Gültigkeitsbereich von lokalen Variablen Durch die Deklaration mit my wird der Gültigkeitsbereich der Variablen eingeschränkt auf den Block, innerhalb dessen sie deklariert worden ist. Nur innerhalb dieses Blockes kann schreibend oder lesend auf sie zugegriffen werden. Lokale Variablen in einem Subroutinenblock sind nur innerhalb dieses Blocks verwendbar. 5.3.3. Übergabe des Argumentwerts an eine lokale Variable in der Subroutine Im folgenden Beispiel wird gezeigt, wie die Elemente der Argumentvariablen an lokale Variablen übergeben werden. Dabei gibt es je nach Datentyp der Argumentvariablen verschiedene Möglichkeiten. Beispiel 5.4: Übergabe der Argumente an Lokale Variablen #!/ usr / bin / perl # file : Subroutinen / uebergabe_lokal . perl # zeigt die Übergabe an Lokale Variablen { use strict ' vars '; my $wert1 =1; my $wert2 =2; my @liste =(1 ,2 ,3); my % lex ; $lex {" ich "}=3; $lex {" du "}=5; & drucke ( $wert1 ); & druckezwei ( $wert1 , $wert2 ); & druckeliste ( @liste ); & druckelexikon (% lex ); } sub drucke ( $ ) { my $w1 = @_[0]; print " Argument $w1 \ n "; } sub druckezwei ( $$ ) { my ( $w1 , $w2 ) = @_; print " Argument eins = $w1 \ n "; print " Argument zwei = $w2 \ n "; } sub druckeliste ( @ ) { my ( @werte ) = @_; my $w ; foreach $w ( @werte ) { print " Argument = $w \ n "; } } sub druckelexikon (%) { my (% lexikon ) = @_; my $w ; foreach $w ( keys % lexikon ) { print " Wort $w = $lexikon { $w }\ n "; } } 78 5. Subroutinen in Perl 5.4. Probleme bei der Übergabe von Argumenten an eine Subroutine Werden in Perl an eine Subroutine Variablen übergeben, dann werden direkte Verweise (sogenannte Aliases) auf die einzelnen Elemente der Argumentvariablen in der STACK Listenvariable @_ gespeichert: • bei Skalaren ein direkter Verweis auf die Variable • bei Listen ein direkter Verweis auf jedes einzelne Element der Liste • bei Hashes direkte Verweise auf die einzelnen Werte der Key/Value Paare In Perl nennt man diese Technik: Linearisierung der Argumentvariablen. Solange eine Subroutine nur mit einem Argument oder mehreren skalaren Argumenten aufgerufen wird, tauchen keine Probleme bei der richtigen Verarbeitung der Argumente innerhalb der Subroutine auf. Problematisch wird es aber, wenn eine Subroutine mit mehreren Argumenten aufgerufen wird und die Argumente in beliebiger Reihenfolge Listen, Skalare und/oder Hashes sind. Der Grund liegt darin, dass Perl alle Argumentvariablen linearisiert, jedoch keine Information über die Art und Anzahl der Argumentvariablen in der STACK Listenvariable @_ speichert. Beispiel 5.5: Linearisierung der Argumentvariablen: my @gerade = (2 ,4 ,6); my @ungerade = (1 ,3 ,5); # Aufruf : & erhoeheWert ( @gerade , @ungerade ) # in der STACK Listenvariable @_ stehen : @ [0] @ [1] @ [2] @ [3] @ [4] @ [5] direkter direkter direkter direkter direkter direkter Verweis Verweis Verweis Verweis Verweis Verweis auf auf auf auf auf auf 2 ,4 ,6 ,1 ,3 ,5 $gerade [0] ... also 2 $gerade [1] ... also 4 $gerade [2] ... also 6 $ungerade [0] ... also 1 $ungerade [0] ... also 3 $ungerade [0] ... also 5 Es besteht kein Hinweis auf die Anzahl der Elemente der beiden Listen und deshalb ist die Zuweisung der STACK Listenvariablen in einer Subroutine an lokale Variablen nicht mehr möglich: sub erhoeheWert ( @@ ) { my ( @ele_gerade , @ele_ungerade ) = @_; ... } # kann nicht funktionieren !!! Das Problem der Linearisierung der Argumentvariablen kann nur gelöst werden, wenn: • die Argumente nur aus Skalaren bestehen, • bei Skalaren und einer Liste/Hash der Skalar als erstes Argument übergeben wird, • bei Argumentvariablen mit unterschiedlichen Datentypen Referenzen auf Argumentvariablen übergeben werden. 5.4. Probleme bei der Übergabe von Argumenten an eine Subroutine 79 5.4.1. Übergabe der Argumentvariable als Referenz: Die Übergabe von Argumenten in Form von Referenzen ist in Perl die einzige Möglichkeit, das Problem der linearisierten Speicherung der Argumentvariablen auf der STACK Listenvariable @_ zu lösen. Intern wird diese Übergabeart dadurch realisiert, dass der Programmierer das Unterprogramm mit einer Referenz auf die Argumentvariable im aufrufenden Programm aufruft. Nun kennt das Unterprogramm die Adresse der Argumentvariablen im aufrufenden Programm und kann deren Wert über den Zugriff der Referenz im aufrufenden Programm lesen und auch verändern. Damit in Perl die Referenz auf eine Variable an ein Unterprogramm übergeben wird, muss man dem Variablennamen der Argumentvariable beim Aufruf einen Backslash voranstellen. Über die Referenz kann man Perl nicht nur die Adresse eines Agruments ermitteln, sondern auch den Datentyp der Argumentvariable. Beispiel 5.6 my @namen = (" Hans " ," Gabi " ," Moni "); & aendere (\ @namen ); # Argumentvariable ist eine Referenz auf das Array @namen Der Subroutine &aendere wird eine Referenz übergeben: Durch Voranstellen eines Backslashs vor den Variablennamen @namen wird aus der Liste @namen eine Referenz auf die Liste. Die Subroutine bekommt als Argument die Referenz der Variablen und speichert sie in einer lokalen Variablen: Beim Zugriff auf eine Argumentvariable, die als Referenz übergeben wurde, muß die Referenzvariable in geschweifte Klammern gesetzt werden und entsprechend des Datentyps unter dem sie angesprochen werden soll der richtige Präfix des Datentyps vorangestellt werden: sub aendere ( @ ) { my ( $liste_referenz ) = @_[0]; # speichern der Referenz # Über die Referenz greift die Subroutine auf die Liste @namen zu # Zugriff auf die gesamte Liste , Ausdrucken der Elemente : print " @ { $liste_referenz }\ n "; # Zugriff auf das erste Element der Liste , Ausdrucken des ersten Elements print " Erster Wert $ { $liste_referenz }[0]\ n "; # # Zugriff auf das erste Element der Liste : Ändern des Werts $ { $liste_referenz }[0] = " Franz "; } 80 5. Subroutinen in Perl Beispiel 5.7: Referenzübergabe an lokale Variable #!/ usr / bin / perl # file : Subroutinen / uebergabe_lokal_referenz . perl # zeigt die Übergabe an Lokale Variablen als Referenz { use strict ' vars '; my $wert1 =1; my $wert2 =2; my @liste =(1 ,2 ,3); my % lex ; $lex {" ich "}=3; $lex {" du "}=5; & drucke (\ $wert1 ); & druckezwei (\ $wert1 ,\ $wert2 ); & druckeliste (\ @liste ); & druckelexikon (\% lex ); } sub drucke (\ $ ) { my ( $adresse ) = @_[0]; # speichere Adresse my $w1 = $ { $adresse }; # Skalar print " Argument $w1 \ n "; } sub druckezwei (\ $ \ $ ) { my ( $w1 , $w2 ) = ( @_); print " Argument eins = $ { $w1 }\ n "; print " Argument zwei = $ { $w2 }\ n "; } sub druckeliste (\ @ ) { my ( $adresse ) = @_[0]; my ( @werte ) = @ { $adresse }; my $w ; foreach $w ( @werte ) { print " Argument = $w \ n "; } } sub druckelexikon (\%) { my ( $adresse ) = @_[0]; my (% lexikon ) =%{ $adresse }; my $w ; foreach $w ( keys % lexikon ) { print " Wort $w = $lexikon { $w }\ n "; } } 5.5. Rückgabewerte von Subroutinen 81 5.4.2. Übergabe der Argumentvariablen als Referenz und Ändern des Wertes der Argumentvariable: Beispiel 5.8: Referenzübergabe und Ändern des Wertes der Argumentvariable #!/ usr / bin / perl # file : Subroutinen / uebergabe_lokal_referenz_aendern . perl # zeigt die Übergabe an Lokale Variablen als Referenz # und ändert den Wert der Argumentvariable { use strict ' vars '; my $wert1 =1; my $wert2 =2; my @liste =(1 ,2 ,3); my % lex ; $lex {" ich "}=3; $lex {" du "}=5; & pluseins (\ $wert1 ); & pluseinsliste (\ @liste ); & pluseinslexikon (\% lex ); } sub pluseins (\ $ ) { my ( $wert_referenz ) = @_[0]; $ { $wert_referenz } = $ { $wert_referenz } +100; } sub pluseinsliste (\ @ ) { my ( $liste_referenz ) = @_[0]; my ( $anz_elem ) = scalar ( @ { $liste_referenz }); for ( my $i =0; $i < $anz_elem ; $i ++) { $ { $liste_referenz }[ $i ] = $ { $liste_referenz }[ $i ] +100; } } sub pluseinslexikon (\%) { my ( $hash_referenz ) = @_[0]; my (% lexikon ) =%{ $hash_referenz }; my $w ; foreach $w ( keys % lexikon ) { $ { $hash_referenz }{ $w } = $ { $hash_referenz }{ $w } + 100; } } 5.5. Rückgabewerte von Subroutinen Ähnlich wie Funktionen in der Mathematik, können Subroutinen in Perl einen Wert an das aufgerufene Programm über ihren Namen zurückgeben. Die Subroutine muss dann innerhalb eines Ausdrucks aufgerufen werden. z.B. in der Mathematik die Berechnung eines sinus Wertes: Die Funktion sinus berechnet den sinus Werts seines Arguments und gibt das Ergebnis über seinen Namen an den Aufrufer zurück: y = sin (2.3) oder y = sin (2.3) * cos (4.0) Welcher Wert zurückgegeben wird legt der Programmierer mit dem return statement im Unterprogramm fest. Stößt die Abarbeitung einer Subroutine auf das return statement, dann wird das Unterprogramm verlassen und der Wert des Ausdrucks der hinter dem return steht als Ergebnis zurückgegeben. In Perl können die Werte aller Ausdrücke zurückgegeben werden. 82 5. Subroutinen in Perl Beispiel 5.9 return " hallo "; return $erg ; return @namen ; # Rückgabe String " hallo " # Rückgabe Wertes in der Variable $erg # Rückgabe Liste @namen 5.6. Globale Variablen Globale Variablen sind solche Variablen, auf die von jeder beliebigen Stelle im gesamten Programm (d.h. auch von allen Subroutinen aus) sowohl lesend als auch schreibend zugegriffen werden kann. Globale Variablen sollten wegen dieser Eigenschaft möglichst vermieden werden, da man nie weiß, in welchem anderen Programmteil der Wert der Variablen nicht eventuell geändert wird, sei es bewusst oder unbewusst (weil z.B. innerhalb eines größeren Programms an anderer Stelle eine Variable gleichen Namens noch einmal definiert wird). Dennoch sind globale Variablen manchmal sinnvoll, z.B. wenn sie wirklich fast überall im Programm benötigt werden und andernfalls in praktisch jedem SubroutinenAufruf explizit als Argument übergeben werden müssten. Beispiel 5.10: Subroutinen #!/ usr / bin / perl # file : Subroutinen / our . perl # zeigt die Verwendung von Globalen Variablen { use strict ' vars '; my $wert1 =1; our $aufrufe =0; # Globale Variable } & drucke ( $wert1 ); & drucke ( $wert1 ); print " Anzahl der Aufrufe = $aufrufe \ n "; sub drucke ( $ ) { my $w1 = @_[0]; print " Argument $w1 \ n "; $aufrufe = $aufrufe + 1; # Zugriff auf globale Variable } 5.6.1. Die Verwendung von our Wird kein use strict verwendet, ist automatisch jede Variable, die nicht speziell mit my deklariert wird, eine globale Variable. Wird jedoch (empfehlenswerterweise) use strict verwendet, können globale Variablen nur mit our deklariert werden. 5.7. Rekursion bei Subroutinen Man spricht von einer rekursiven Subroutine, wenn in den Abarbeitungsschritten, sprich dem Rumpf der Subroutine, die Routine selbst wieder aufgerufen wird: Die Mathematik spricht von einer rekursiven Funktion, wenn sie sich durch sich selbst definiert. Die Verwendung der Rekursion in einer Programmiersprache hängt davon ab, ob ein STACKMechanismus implementiert ist, der sich von einem Aufruf zum nächsten Zwischenwerte merken kann. Dieser STACK-Mechanismus ist in PERL definiert und somit kann die Rekursion in PERL verwendet werden. 5.8. Exkurs: Übergabemechanismus in Perl im Detail (für den Spezialisten) : 83 Beispiel 5.11: Fakultät Iterativ: 5! = 1 · 2 · 3 · 4 · 5 sub fak_iterativ () { my $zahl = @_[0]; my $erg = 1; my $i ; if ( $zahl <= 0) { return 0 }; for ( $i =1; $i <= $zahl ; $i ++) { $erg = $erg * $i ; } return $erg ; } Rekursiv: Idee: 5! 120 = 5 * 4 * 3 * 2 * 1 = 5 * ( 4 * 3 * 2 * 1) = 5 * 4! 4! = 4 * ( 3 * 2 * 1 ) = 4 * 3! 3! = 3 * ( 2 * 1 ) = 3 * 2! 2! = 2 * 1! 1! = 1 ( hier terminiert die Fakultät ) = 2 * 1 = 3 * 2 = 4 * 6 = 5 * 24 sub fak_rek () { my $zahl = @_[0]; if ( $zahl ==1) { return 1; } else { return $zahl * & fak_rek ( $zahl -1); } } 5.8. Exkurs: Übergabemechanismus in Perl im Detail (für den Spezialisten) : Der Standardübergabemechanismus der Programmiersprache Perl ist eine Mischung von „call by value“ und „call by reference“. Diese Mischung führt bei ungeübten Programmierern schnell zu Verwirrung und Programmierfehlern und letztendlich zu einer Vermeidung von selbstgeschriebenen Subroutinen. In Perl erinnert die Aufrufart einer Subroutine an „call by value“, jedoch werden intern dem Unterprogramm nicht eine Kopie der Argumente übergeben, sondern sogenannte Aliases der einzelnen Argumente. Aliases sind Verweise auf die Speicheradresse einer Variablen. Eine Subroutine kann somit lesend und schreibend auf seine Argumente zugreifen. Problematisch wird diese Mischform, wenn Listen übergeben werden, da dann durch Perl die Liste linearisiert wird und die Adressen der einzelnen Arrayelemente übergeben werden. 84 5. Subroutinen in Perl Das Unterprogramm weiß gar nicht mehr, dass das Argument mit dem es aufgerufen wurde, eine Liste war. Erst mit der Version 5 der Programmiersprache Perl wurde der Übergabemechanismus „call by reference“ eingeführt. Jetzt können Argumente mit ihren Adressen übergeben werden. Das Unterprogramm bekommt die Information über den Variablentyp und über die Adresse der aufrufenden Argumente. Skalare im aufrufenden Programm bleiben Skalare im Unterprogramm und Listen bleiben im Unterprogramm Listen. Auf jedes Argument kann über die Adresse zugegriffen werden. Bei den Systemroutinen, die von Perl verwendet werden, müssen die Argumente laut Definition der Subroutine übergeben werden. In den meisten Fällen ist dies bei Perl die Aufrufart „call by value“. Durch Vorstellen des Referenzoperators \ vor den Variablennamen wird in Perl automatisch die Adresse einer Variable angesprochen. $name \ $name Wert der Variable $name Adresse der Variable $name Um einer Subroutine Argumente nach der Aufrufart „call by reference“ zu übergeben, muss man vor die Variablennamen der Subroutineargumenten immer ein Backslash schreiben. 5.8.1. Der STACK Speicher bei Subroutinenaufrufen Damit zwischen Unterprogrammen und aufrufendem Programm Daten ausgetauscht werden können, wird bei Perl ein spezieller Speicher reserviert, auf den sowohl das Unterprogramm als auch das aufrufende Programm zugreifen kann. Dieser Speicherbereich heißt STACK. Der STACK ist wie eine Liste organisiert und bekommt in Perl den reservierten Listenvariablennamen @_. In die Liste @_ werden beim Aufruf des Unterprogramms automatisch die Werte bzw. Adresse des Arguments bzw. der Argumentvariable, je nach Aufrufart, eingetragen. Das Unterprogramm und das aufrufende Programm kann aus dieser Liste die Werte lesen. Hier ein Beispiel zur Demonstration der Aufrufart „call by value“ und „call by reference“ Beispiel 5.12: „call by value“, „call by reference“ # Hauptprogramm { my $text = " hallo "; my $name = " Sepp "; my @farben = (" rot " ," grün " ," blau "); } Adressbuch des Hautprogramm: NAME $text $name @farben ADRESSE 1000 2000 3000 3020 3040 TYP und WERT Typ: Skalar, Wert=”Hallo” Typ: Skalar, Wert=”Sepp” Typ: Liste, Werte = ”rot” ”grün” ”blau” 5.9. Beispiel: Berechnung des Wochentags in Abhängikeit vom Datum 85 1.Fall: Aufruf einer Systemroutine ⇒ Aufrufsart = Call by Value Die Argumente werden entweder als Konstante oder als Variable übergeben: Aufruf: print (" Hallo "); NAME STACKSPEICHER ADRESSE 10000 TYP und WERT Typ: Skalar, Wert=”Hallo” get ( $name ); NAME STACKSPEICHER ADRESSE 10000 TYP und WERT Typ: Skalar, Wert=”Sepp”, Alias auf 2000 print ( @farben ); NAME STACKSPEICHER ADRESSE 10000 TYP und WERT Typ: Skalar, Wert=”rot”, Alias auf 3000 Typ: Skalar, Wert=”grün”, Alias auf 3020 Typ: Skalar, Wert=”blau”, Alias auf 3040 sort ( @liste ); NAME STACKSPEICHER ADRESSE 10000 TYP und WERT Typ: Skalar, Wert=”rot”, Alias auf 3000 Typ: Skalar, Wert=”grün”, Alias auf 3020 Typ: Skalar, Wert=”blau”, Alias auf 3040 2. Fall: Aufruf einer eigenen Subroutine ⇒ Aufrufsart = Call by Reference Es muss die Adresse der Argumente übergeben werden. Durch Voranstellen eines Backslashs wird automatisch die Adresse einer Variable angesprochen. Aufruf: verändere_farben (\ @farben ); NAME @_STACKSPEICHER ADRESSE 10000 TYP und WERT Typ: Liste, Wert=3000 konvertiere (\ $name ,\ $text ); NAME STACKSPEICHER ADRESSE 10000 10010 TYP und WERT Typ: Skalar, Wert=1000 Typ: Skalar, Wert=2000 5.9. Beispiel: Berechnung des Wochentags in Abhängikeit vom Datum Beispiel 5.13: Subroutinen #!/ usr / bin / perl # file :/ Subroutinen / wochentag . perl # Berechnet den Wochentag in Abhängigkeit von einem Datum use strict ' vars '; 86 5. Subroutinen in Perl # # # # # # # ############# Teste Schaltjahr # # # # # # # # # # # # # # # # # # # # # # # # # # # sub schaltjahr ( $jahr ) { my ( $jahr ) = @_; return ( ( ( $jahr % 4 == 0 ) && ( $jahr % 100 != 0 ) ) || ( $jahr % 400 == 0 ) ); } # # # # # # # ############# Zähle Tage im Monat # # # # # # # # # # # # # # # # # # # # # # # # # # # sub tage_im_monat ( $monat , $jahr ) { my ( $monat , $jahr ) = @_; if ( $monat == 1 || $monat == 3 || $monat == 5 || $monat == 7 || $monat == 8 || $monat == 10 || $monat == 12 ) { return 31; } if ( $monat == 4 || $monat == 6 || $monat == 9 || $monat == 11 ) { return 30; } } if ( $monat == 2 ) { if ( & schaltjahr ( $jahr ) ) { return 29; } else { return 28; } } print (" Falscher Monat , Nummer = $monat \ n "); return 0; # # # # # # # ############# Zähle restliche Tage im Monat # # # # # # # # # # # # # # # # # # # # # # # # # # # sub restliche_tage_im_monat ( $tag , $monat , $jahr ) { my ( $tag , $monat , $jahr ) = @_; if ( $jahr > 1993 ) { return $tag ; } else { return ( & tage_im_monat ( $monat , $jahr ) - $tag ); } } # # # # # # # ############# Zähle restliche Tage im Jahr # # # # # # # # # # # # # # # # # # # # # # # # # # # sub restliche_tage_im_jahr ( $tag , $monat , $jahr ) { my ( $tag , $monat , $jahr ) = @_; my ( $summe , $index ); } $summe = 0; if ( $jahr > 1993 ) { for ( $index = 1 ; $index < $monat ; $index ++ ) { $summe = $summe + & tage_im_monat ( $index , $jahr ); } return $summe + $tag ; } else { for ( $index = 12 ; $index > $monat ; $index - - ) { $summe = $summe + & tage_im_monat ( $index , $jahr ); } return $summe + & restliche_tage_im_monat ( $tag , $monat , $jahr ); } 5.9. Beispiel: Berechnung des Wochentags in Abhängikeit vom Datum 87 # # ################## Zähle Tage im Jahr # # # # # # # # # # # # # # # # # # # # # # # # # # # sub tage_im_jahr ( $jahr ) { my ( $jahr ) = @_; if ( & schaltjahr ( $jahr ) ) { return 366; } else { return 365; } } # # ################## Zähle Tage # # # # # # # # # # # # # # # # # # # # # # # # # # # sub anzahl_der_tage ( $tag , $monat , $jahr ) { my ( $tag , $monat , $jahr ) = @_; my ( $summe , $index ); $summe = 0; if ( $jahr > 1993 ) { for ( $index = 1994 ; $index < $jahr ; $index ++ ) { $summe = $summe + & tage_im_jahr ( $index ); } return ( $summe + & restliche_tage_im_jahr ( $tag , $monat , $jahr ) ); } else { for ( $index = 1993 ; $index > $jahr ; $index - - ) { } } $summe = $summe + & tage_im_jahr ( $index ); } return ( $summe + & restliche_tage_im_jahr ( $tag , $monat , $jahr ) ); # # ################## Bestimme Wochentag # # # # # # # # # # # # # # # # # # # # # # # # # # # sub wochentag_nummer ( $tag , $monat , $jahr ) { my ( $tag , $monat , $jahr ) = @_; if ( $jahr > 1993 ) { return ( & anzahl_der_tage ( $tag , $monat , $jahr ) % 7 ); } else { return ( ( 7 - ( & anzahl_der_tage ( $tag , $monat , $jahr ) % 7 ) ) % 7 ); } } ### Hauptprogramm : { my ( $tag , $tage , $jahr , $monat , $gesuchter_tag ); print (" Hallo , hier ist Wochentag \ n "); print (" Bitte Jahr eingeben > > > >"); $jahr = < stdin >; chomp ( $jahr ); if ( & schaltjahr ( $jahr ) != 0 ) { print (" Schaltjahr \ n "); } else { print (" Kein Schaltjahr \ n "); } print (" Bitte Monat eingeben > > > >"); $monat = < stdin >; chomp ( $monat ); $tage = & tage_im_monat ( $monat , $jahr ); print (" Anzahl der Tage im Monat $monat = $tage \ n "); 88 5. Subroutinen in Perl print (" Bitte Tag eingeben > > > >"); $tag = < stdin >; chomp ( $tag ); print (" Der gesuchte Wochentag ist ein "); $gesuchter_tag = & wochentag_nummer ( $tag , $monat , $jahr ); if if if if if if if ( ( ( ( ( ( ( $gesuchter_tag $gesuchter_tag $gesuchter_tag $gesuchter_tag $gesuchter_tag $gesuchter_tag $gesuchter_tag == == == == == == == 0 1 2 3 4 5 6 ) ) ) ) ) ) ) { { { { { { { print (" Freitag "); } print (" Samstag "); } print (" Sonntag "); } print (" Montag "); } print (" Dienstag "); } print (" Mittwoch "); } print (" Donnerstag "); } print ("\ n "); ## Falls Library da ist : ## use Date :: Calc qw ( Day_of_Week Day_of_Week_to_Text Language Decode_Language ); ################ Als Libraryaufruf ... # $gesuchter_tag = Day_of_Week ( $jahr , $monat , $tag ); # Language ( Decode_Language (" Deutsch ")); # print " Aus der Libray " , Day_of_Week_to_Text ( $gesuchter_tag ) ," \ n "; # # # # # # # # # # # # # # # # # # # # # # # # # # # Ende # # # # # # # # # # # # # # # # # # # # # # # # # # # # } 6. Aufgaben und Lösungen 6.1. Aufgabe: größte/kleinste Zahl Schreiben Sie ein Perl Programm, das den Benutzer auffordert 3 Zahlen einzulesen und die größte und kleinste Zahl der drei eingegebenen Zahlen ausgibt. #!/ usr / bin / perl -w # file : / AufgabenLoesungen / groeste - kleinsteZahl . perl # Auffinden der groesten bzw . kleinsten Zahl use strict ; { my ( $a , $b , $c , $groesste_zahl , $kleinste_zahl ); print (" Bitte drei Zahlen eingeben .\ n "); print (" Zahl 1: "); $a = < >; print (" Zahl 2: "); $b = < >; print (" Zahl 3: "); $c = < >; chomp ( $a , $b , $c ); } if ( $a >= $b ) { $groesste_zahl = $a ; $kleinste_zahl = $b ; if ( $c > $a ) { $groesste_zahl = $c ; } if ( $c < $b ) { $kleinste_zahl = $c ; } } if ( $b > $a ) { $groesste_zahl = $b ; $kleinste_zahl = $a ; if ( $c > $b ) { $groesste_zahl = $c ; } if ( $c < $a ) { $kleinste_zahl = $c ; } } print (" Groesste Zahl : $groesste_zahl \ n "); print (" Kleinste Zahl : $kleinste_zahl \ n "); 6.2. Aufgabe: Alphabetischer Vergleich Lesen Sie zwei Zeichenketten ein und geben Sie die alphabetisch ’kleinere’ und die alphabetisch ’größere’ Zeichenkette aus. $a = < >; $b = < >; 89 90 6. Aufgaben und Lösungen if ( $a lt $b ) { print (" alphabetisch print (" alphabetisch } else { print (" alphabetisch print (" alphabetisch kleinere Zeichenkette : $a "); größere Zeichenkette : $b "); kleinere Zeichenkette $b "); größere Zeichenkette : $a "); } 6.3. Aufgabe: Fakultät (iterativ, rekursiv) Berechnen Sie die Fakultät einer Zahl: Das Programm soll nach einer Zahl fragen und die Fakultät dieser Zahl berechnen. Beispiel: Die Fakultät der Zahl 5 = 5 · 4 · 3 · 2 · 1 #!/ usr / bin / perl -w # file :/ AufgabenLoesungen / fakultaet . pl # Iterative Lösung der Fakultät use strict ; { my ( $eingabe , $fakultaet , $zaehler ); print (" Gib eine Zahl ein : "); $eingabe = < >; chomp $eingabe ; $zaehler = 1; $fakultaet = 1; while ( $zaehler <= $eingabe ) { $fakultaet = $fakultaet * $zaehler ; $zaehler ++; } print (" Die Fakultaet von $eingabe ist $fakultaet \ n "); } #!/ usr / bin / perl -w # file :/ AufgabenLoesungen / fakultaetRekursiv . pl # Rekursive Lösung der Fakultät use strict ; { my ( $eingabe , $result ); print (" Gib eine Zahl ein : "); $eingabe = < >; chomp $eingabe ; $result = & fak ( $eingabe ); print (" Die Fakultaet von $eingabe ist $result \ n "); } ####################################### sub fak ( $ ) { my $zahl = $_[0]; if ( $zahl == 1 ) { print (" letzter Aufruf \ n "); print ("..... Terminiere mit Eins \ n "); return 1; } else { return $zahl * & fak ( $zahl - 1 ); } } 6.4. Aufgabe: Einlesen einer Rechenaufgabe 91 6.4. Aufgabe: Einlesen einer Rechenaufgabe Wie lautet ein Perl-Programm, das dem Benutzer 4 leichte Rechenaufgaben in Form eines Textes auf das Terminal schreibt und den Benutzer nach jeder Rechenaufgabe auffordert, das Rechenergebnis einzugeben? Das Programm liest die Eingabe und überprüft, ob das Ergebnis stimmt. Das Programm soll die Anzahl der richtigen Antworten zählen und am Schluss ausgeben, wieviele Ergebnisse richtig waren. Falls alle vier Aufgaben richtig gerechnet wurden, soll ein besonderes Lob auf das Terminal geschrieben werden. #!/ usr / bin / perl -w # file :/ AufgabenLoesungen / einlesenRechen . pl # Einlesen einer Rechenaufgabe use strict ; { my ( $zahl , $richtig ); $richtig = 0; print (" AUSGABE : Welchen Wert hat 2+2?\ n "); print (" EINGABE : "); $zahl = < >; chomp $zahl ; if ( $zahl == ( 2 + 2 ) ) { $richtig ++; } print (" AUSGABE : Welchen Wert hat 2*3?\ n "); print (" EINGABE : "); $zahl = < >; chomp $zahl ; if ( $zahl == ( 2 * 3 ) ) { $richtig ++; } print (" AUSGABE : Welchen Wert hat 10/5?\ n "); print (" EINGABE : "); $zahl = < >; chomp $zahl ; if ( $zahl == ( 10 / 5 ) ) { $richtig ++; } print (" AUSGABE : Welchen Wert hat 3 + 4 + 5?\ n "); print (" EINGABE : "); $zahl = < >; chomp $zahl ; if ( $zahl == ( 3 + 4 + 5 ) ) { $richtig ++; } } if ( $richtig == 4 ) { print (" Du bist der Wahnsinn ! So schwere Aufgaben ...\ n "); } else { print (" $richtig Aufgaben richtig gelöst .\ n "); } 92 6. Aufgaben und Lösungen 6.5. Aufgabe: Wörter mit Selbstlauten extrahieren Schreiben Sie ein Perl Programm, das eine Datei selbstlaute_woerter.txt erzeugt, in die alle Wörter aus der Datei wortliste.txt kopiert werden, die mit einem Selbstlaut a,e,i,o,u beginnen. Tipp: Lesen Sie wieder jedes Wort aus der Wortliste und zerlegen Sie jedes Wort mit split. Testen sie ob der erste Buchstabe ein Selbstlaut ist. #!/ usr / bin / perl -w # file :/ AufgabenLoesungen / selbstlaute . pl # Wörter mit Selbstlauten extrahieren use strict ; { my ( $dateiname , $ausgabe , $zeile ); my ( @buchstaben ); $dateiname = " wortliste . txt "; $ausgabe = " selbstlaute_woerter . txt "; open ( DATEI , $dateiname ); open ( AUSGABE , " > $ausgabe "); } while ( $zeile = < DATEI > ) { chomp $zeile ; @buchstaben = split ( // , $zeile ); if ( ( lc ( $buchstaben [0]) eq " a " || ( lc ( $buchstaben [0]) eq " e " || ( lc ( $buchstaben [0]) eq " i " || ( lc ( $buchstaben [0]) eq " o " || ( lc ( $buchstaben [0]) eq " u " { print AUSGABE " $zeile \ n "; print " $zeile \ n "; } } close DATEI ; close AUSGABE ; ) ) ) ) ) ) 6.6. Aufgabe: Buchstaben zählen Schreiben Sie ein Perl Programm, das die Buchstaben in der Datei wortliste.txt liest und die Anzahl der Buchstaben zählt und ausgibt.(Tipp: Verwenden Sie die Perl Routine length) #!/ usr / bin / perl -w # file :/ AufgabenLoesungen / buchstaben . pl # Buchstaben zählen use strict ; { my ( $dateiname , $zeile , $buchstabenzahl , $gesamtanzahl ); $dateiname = " wortliste . txt "; $gesamtanzahl = 0; open ( DATEI , $dateiname ); while ( $zeile = < DATEI > ) { chomp $zeile ; $buchstabenzahl = length ( $zeile ); $gesamtanzahl = $gesamtanzahl + $buchstabenzahl ; } close DATEI ; 6.7. Aufgabe: Passwort abfragen } 93 print (" Die Anzahl der Buchstaben betraegt $gesamtanzahl \ n "); 6.7. Aufgabe: Passwort abfragen Schreiben Sie ein Passwort-Perl Programm: In der Datei passwd.txt steht das Passwort. Das Perl Programm soll aus dieser Datei das aktuelle Passwort lesen und den Benutzer maximal fünf Mal nach dem Passwort fragen. Jedes Passwort, auch ein falsches, das der Benutzer eingibt, soll in der Datei passwd.log gespeichert werden. #!/ usr / bin / perl -w # file :/ AufgabenLoesungen / passwort . pl # Passwort abfragen use strict ; { my ( $dateiname , $zeile , $ausgabedatei , $passwort , $zaehler , $geraten ); my ( @letters ); $dateiname = " passwd . txt "; $ausgabedatei = " passwd . log "; open ( DATEI , $dateiname ); while ( $zeile = < DATEI > ) { chomp $zeile ; $passwort = $zeile ; } close DATEI ; open ( AUSGABE , " > $ausgabedatei " ); print (" Bitte Passwort eingeben :\ n "); $geraten = < STDIN >; chomp $geraten ; print AUSGABE (" $geraten \ n "); $zaehler = 1; while ( ( $zaehler < 5 ) && ( $geraten ne $passwort ) ) { print (" Falsch . Naechster Versuch :\ n "); $geraten = < STDIN >; chomp $geraten ; print AUSGABE (" $geraten \ n "); $zaehler ++; } } if ( $geraten eq $passwort ) { print (" Richtig .\ n "); } close AUSGABE ; 94 6. Aufgaben und Lösungen 6.8. Aufgabe: Wörter mit drei Buchstaben Speichern Sie alle drei Buchstaben lange Wörter des Textes info.txt in der Datei drei.txt. #!/ usr / bin / perl -w # file :/ AufgabenLoesungen / dreiBuchstaben . pl # Ausgeben von Strings in eine Textdatei use strict ; { my ( $text , $zeile , $zaehler , $ausgabe ); my ( @woerter ); my % anzahl ; $text = " info . txt "; $ausgabe = " drei . txt "; open ( INFO , $text ); open ( DREI , " > $ausgabe " ); } while ( $zeile = < INFO > ) { chomp $zeile ; @woerter = split ( /[ ,. ;:]+/ , $zeile ); foreach my $wort ( @woerter ) { if ( length ( $wort ) == 3 ) { print DREI (" $wort \ n "); } } } close INFO ; close DREI ; print (" Ausgabe in $ausgabe geschrieben .\ n "); 6.9. Aufgabe: Wörter zählen Erweitern Sie das vorige Perl-Programm, um alle kleingeschrieben und großgeschriebenen Wörter in einer Datei mit UTF8-codierung zu zählen. Bitte setzen Sie dabei alle Kanäle auf UTF8. #!/ usr / bin / perl # file :/ AufgabenLoesungen / kleinWoerter . pl # Berechnen von groß - bzw . kleingeschriebene Wörter einer Textdatei use strict ; { my ( $zeile , $klein , $gross ); $gross = 0; $klein = 0; my ( @woerter , @buchstaben ); binmode ( STDIN , ": utf8 " ); # Setzt STDIN auf utf -8 binmode ( STDOUT , ": utf8 " ); # Setzt STDOUT auf utf -8 open ( LESEN , " <: utf8 " , " sz_artikel . txt " ); while ( $zeile = < LESEN > ) { chomp $zeile ; @woerter = split ( /[ ,. ;:\(\)\/\*\"]+/ , $zeile ); foreach my $wort ( @woerter ) { @buchstaben = split ( // , $wort ); if ( $buchstaben [0] =~ /[ a - zäöü ]/ ) { $klein ++; } if ( $buchstaben [0] =~ /[ A - ZÄÖÜ ]/ ) { $gross ++; } } 6.10. Aufgabe: Split von Zeilen und Wortliste } 95 } close LESEN ; print (" Gross geschrieben : $gross Woerter \ n "); print (" Klein geschrieben : $klein Woerter \ n "); 6.10. Aufgabe: Split von Zeilen und Wortliste Lesen Sie die Datei zeilenweise ein und verwenden Sie die Perl Routine split um die Zeilen des Artikels in Wörter aufzuspalten. #!/ usr / bin / perl # file :/ AufgabenLoesungen / zeilenSplit . perl # Split von Zeilen und Wortliste use strict ; { my ( $zeile ); my ( @woerter ); open ( LESEN , " sz_artikel . txt " ); } while ( $zeile = < LESEN > ) { chomp $zeile ; @woerter = split ( /[ ,. ;:\(\)\/\*\"]+/ , $zeile ); foreach my $wort ( @woerter ) { print " $wort \ n "; } } close ( LESEN ); # (*) siehe unten Zeichen wie (, ), /, *, \ oder ” haben eine eigene Bedeutung im regulären Ausdruck. Diese Metabedeutung wird durch einen vorangestellten Backslash aufgehoben. Erweitern Sie das Perl-Programm um alle Wörter des sz Artikels in einen Hash einzufügen und alphabetisch sortiert auszugeben. Die Wörter sollen alphabetisch sortiert in der Datei wort_sort.txt gespeichert werden. #!/ usr / bin / perl -w # file :/ AufgabenLoesungen / zeilenSplitHash . perl # Erzeugen einer Frequenzliste use strict ; { my ( $zeile ); my ( @woerter ); my % worthash ; open ( LESEN , " sz_artikel . txt " ); open ( SORT , " > wort_sort . txt " ); while ( $zeile = < LESEN > ) { chomp $zeile ; @woerter = split ( /[ ,. ;:\(\)\/\*\"]+/ , $zeile ); foreach my $wort ( @woerter ) { $worthash { $wort }++; } } close LESEN ; } foreach my $wort ( sort keys % worthash ) { print SORT " $wort \ n "; } print (" Sortiert in wort_sort . txt gespeichert !\ n "); close SORT ; 96 6. Aufgaben und Lösungen 6.11. Aufgabe: Frequenzliste Schreiben Sie ein Programm, das den Artikel der sz.txt liest und die 10 am häufigsten vorkommenden grossgeschriebenen Wörter und die 10 am häufigsten vorkommenden kleingeschriebenen Wörter ausgibt. Tipp: Füllen Sie zwei Hashes, einen für die kleingeschriebenen Wörter und einen für die großgeschriebenen Wörter. Um zu entscheiden, ob ein Wort groß oder kleingeschrieben wird, verwenden Sie in einer if Anfrage reguläre Ausdrücke (siehe script) #!/ usr / bin / perl -w # file :/ AufgabenLoesungen / haeufigsten10 . pl # Top 10 Wörter auflisten mithilfe von Frequenzliste use strict ; { my ( $zeile , $zaehler ); my ( @woerter , @buchstaben ); my ( % hash_klein , % hash_gross ); open ( LESEN , " sz_artikel . txt " ); while ( $zeile = < LESEN > ) { chomp $zeile ; @woerter = split ( /[ ,. ;:\(\)\/\*\"]+/ , $zeile ); foreach my $wort ( @woerter ) { @buchstaben = split ( // , $wort ) unless $wort eq ""; if ( $buchstaben [0] =~ /[ a - zäöü ]/ ) { $hash_klein { $wort }++; } if ( $buchstaben [0] =~ /[ A - ZÄÖÜ ]/ ) { $hash_gross { $wort }++; } } } $zaehler = 0; print " Klein geschrieben : \ n "; foreach my $kleines_wort ( sort { $hash_klein { $b } <= > $hash_klein { $a } } keys % hash_klein ) { if ( $zaehler != 10 ) { print (" $kleines_wort = $hash_klein { $kleines_wort }\ n "); $zaehler ++; } } $zaehler = 0; print "\ nGross geschrieben : \ n "; foreach my $gross_wort ( sort { $hash_gross { $b } <= > $hash_gross { $a } } keys % hash_gross ) { if ( $zaehler != 10 ) { print (" $gross_wort = $hash_gross { $gross_wort }\ n "); $zaehler ++; } } } 7. Linux 7.1. Einführung in Linux 7.1.1. Einleitung Nach Bearbeitung dieses Kapitels können Sie grundlegende Eigenschaften von Linux Systemen verstehen. 7.1.2. Eigenschaften • Multi-User-Betrieb Am System können mehrere Benutzer gleichzeitig arbeiten. Sie werden über den Benutzernamen unterschieden. • Multi-Tasking Am System können mehrere Programme gleichzeitig arbeiten. • Timesharing Programme werden über Prioritäten verwaltet und bekommen abwechselnd die CPU(s). • Interaktivität Jeder Benutzer kann mit einem Terminal interaktiv arbeiten. • Hierarchisches Dateisystem Alle Dateien werden über eine Baumstruktur verwaltet. • Benutzerschnittstelle (Shell) Der Benutzer kommuniziert mit Linux über eine Kommandosprache, die Shell heißt. • grafische Benutzerschnittstelle(GUI) z.B. via X11-Server, KDE und Gnome. • Programmentwicklung Unter Linux gibt es zahlreiche Werkzeuge zur Programmerstellung. • Textverarbeitung Unter Linux gibt es zahlreiche Programme zur Textverwaltung. • Netzwerkunterstützung Jedes Linux kann in einem TCP/IP Netzwerk arbeiten. Unterstützt netzwerkweite Dateisysteme (NFS), mail, Programme usw. • Kernel Kontrolliert die Hardware 97 98 7. Linux Memory Management Unit CPU Vergabe über Prioritäten Geräte Ein/Ausgabe • System Dienste Arbeiten direkt mit dem Kernel zusammen Die Systemdienste stehen als C-Programme zur Verfügung. • Dienstprogramme Komplexe Programme als Linux Befehle • Benutzerschnittstelle Es stehen verschiedene Shells zur Verfügung : bash, zsh • Grafische Benutzerschnittstelle basierend auf X11: KDE, Gnome und andere Abbildung 7.1.: Graphische Darstellung des LINUX-Systems 7.2. Verwalten von Dateien Teil 1 7.2.1. Einleitung Nach Bearbeitung dieses Kapitels können Sie : • Das Linux Dateisystem verstehen. • Verzeichnisse, Dateien und Gerätedateien unterscheiden. • Die wichtigsten Aufgaben zum Verwalten von Dateien durchführen. • Dateibezeichnungen korrekt eingeben. 7.2. Verwalten von Dateien Teil 1 99 7.2.2. Das Linux Dateisystem 7.2.2.1. Der hierarchische Dateibaum Alle Linux Dateien sind streng hierarchisch baumartig organisiert. Der Ausgangspunkt des Dateibaums ist das root Directory ”/”, auch Stammverzeichnis genannt, das auf weitere Dateien oder Verzeichnisse verweist. Es gibt keine Laufwerksbuchstaben. Bei Linux gibt es Standardverzeichnisse in denen Dateien für spezielle Aufgaben zusammengefasst sind. Wichtige Standardverzeichnisse und die Aufgaben ihrer Dateien sind: Verzeichnis / / sbin / / bin / / boot / / dev / / home / / root / / tmp / / usr / / usr / bin / / usr / X11R6 / bin / / usr / src / / var / / var / log / / proc / / opt / / mnt / / media / etc / / etc / init . d / / etc / X11 / / lib / / usr / lib / kurze Beschreibung root - Verzeichnis ( Basisverzeichnis ) Programme für den Systemverwalter allgemeine Kommandozeilen - Befehle ( GNU - Programme ) Verzeichnis für Startdateien und den Kernel Gerätedateien ( für Tastatur , Maus , Modem , Festplatte , CDROM , ...) Benu tzer verz eichn isse Verzeichnis des Systemverwalters temporäre Dateien Dateien / Programme für die Benutzer Anwendungsprogramme für die Benutzer Anwendungsprogramme für die grafische Oberfläche Quellcodes ( z . B . vom Linux - Kernel ) Verzeichnis für sich ändernde Daten ( Mailverzeichnis , Druckerspooler , ...) Protokoll - Dateien Systeminformationen ; Schnittstelle zum Kernel optionale Programme ( teilweise KDE , Firefox ) Mount - Point für Disketten , CD - ROMs , etc ... Mount - Point für externe Festplatten , USB - Sticks , CD - ROMs usw . systemweite Konf igur atio nsdat eien Start -/ Stopscripte der Systemdienste Konf igur atio nsdat eien von xorg allgemeine Programm - Bibliotheken ( Programmlader , Hauptbibliothek glibc ) Programm - Bibliotheken für Anwendungsprogramme Jeder User arbeitet zu jedem Zeitpunkt in einem Working Directory, das er mit dem Befehl cd (change Directory) ändern und mit dem Befehl pwd (print Working Directory) ausgeben kann. Unter Linux können Verzeichnisse deviceübergreifend auf beliebigen Datenträgern abgespeichert werden. Der Systemadministrator bindet die Verzeichnisse an eine beliebige Stelle des Dateibaumes ein (mount), wobei sich an der hierarchischen Dateistruktur nichts ändert. Der User merkt auch nicht auf welcher physikalischen Platte er momentan arbeitet. (Abfrage mit ”df .”) Eine aktuelle Zusammenfassung des hierarchischen Dateisystems findet sich unter https://de.wikipedia.org/wiki/Filesystem_Hierarchy_Standard 7.2.2.2. Verzeichnisse, Dateien und Gerätedateien In Linux gibt es • gewöhnliche Dateien Textdateien, am Terminal ausgebbar Binärdateien, Programmdateien • Verzeichnisse Sammlung von anderen Dateien, die selbst Verzeichnisse sein können 100 7. Linux • spezielle Dateien Gerätedateien in denen die Routinen des Linux Kernels abgespeichert sind, die die Einund Ausgabe auf physikalische Geräte realisieren. Jedes Gerät hat für jede Schnittstelle ein eigenes Devicefile. Wichtige Gerätedateien sind : / dev / sd * / dev / hd * / dev / console / dev / tty01 / dev / null / dev / sr * / dev / zero : Festplatten , allgemein Datenträger , also auch usb - memory - sticks : Festplatten , mit alten Treiber /p - ata : System Konsole : asynchrones Terminal : Null - Device : CD - Rom : Zero - Device 7.2.3. Fallbeispiel zum Verwalten von Dateien 7.2.3.1. Das Anlegen von Dateien In den nächsten Kapiteln werden Datei- und Verzeichnisoperationen anhand eines Fallbeispiels erklärt. Es gibt 3 Studenten: meier, huber und schoch Es ergibt sich folgende hierarchische Dateistruktur. Abbildung 7.2.: Hierarchische Dateistruktur von LINUX Zum Anlegen von Dateien gibt es unter Linux die Möglichkeit, die Terminaleingabe in eine Datei umzuleiten (Befehl cat) oder einen Texteditor aufzurufen. Achtung : Unter Linux werden ältere Versionen von Dateien nicht automatisch gesichert, sondern stets überschrieben. Beispiel 7.1 > pwd / mounts / users / student / meier Im Bereich Holzbau soll für den Dachbau eine neue Datei dach angelegt werden: Beispiel 7.2 > cat > text1 . txt > touch text2 . txt : Schreibt Terminaleingabe in die Datei text1 . txt , Beenden der Eingabe mit CTRL d : Kreiert eine leere Datei mit dem Namen text2 . txt 7.2. Verwalten von Dateien Teil 1 101 7.2.3.2. Das Anzeigen von Inhaltsverzeichnissen Der Inhalt des Verzeichnisses wird mit dem Befehl ls ausgegeben: wichtige Optionen des Befehls ls: -a listet auch die verborgenen Dateien (der Dateiname beginnt mit einem Punkt) im Verzeichnis auf. -l langes (ausführliches) Ausgabeformat In jedem Verzeichnis gibt es immer die zwei verborgenen Dateien: . Zeigt auf das eigene Verzeichnis .. Zeigt auf das Elternverzeichnis -F hängt dem Dateiname ein Metazeichen an, das den Dateityp anzeigt: \ für Verzeichnis * für ausführbar Beispiel 7.3 Benutzer huber nach dem einloggen: > pwd / mounts / users / student / huber > ls briefe seminar text . txt > ls - aF ./ ../ briefe / seminar / text . txt 7.2.3.3. Länge und Zeichenkonventionen von Dateinamen Bei Datei- und Verzeichnisnamen können mit 254 Bytes nicht unbedingt 254 Stellen genutzt werden. Sonderzeichen und Umlaute sind nach Möglichkeit zu vermeiden aber nicht ausgeschlossen (Dateiname wird utf-8 codiert). Groß- und Kleinschreibung wird unterschieden(case sensitiv). Ein Name sollte nicht mit einem Punkt (nur bei explixiter verborgener Datei) oder mit einem Minus beginnen (Name könnte als Befehlsoption behandelt werden). Im Dateinamen sollte kein ”*” stehen. Wenn sich Sonderzeichen nicht vermeiden lassen, müssen sie mit besonderer Sorgfalt eingegeben werden: z.B. ”\ ” für Space. Der Schrägstrich / ist verboten da er als Trenner im Pfadnamen fungiert. 7.2.3.4. Das Löschen von Dateien Unter Linux können Dateien (Befehl rm) und Verzeichnisse mit ihren Unterverzeichnissen (Befehl rm -r) gelöscht werden. Beispiel 7.4 Es sollen die Datei text.txt und das Verzeichnis seminar mit allen Dateien gelöscht werden: > pwd / mounts / users / student / huber > rm text . txt > rm -r seminar 102 7. Linux Um Dateien zu entfernen, deren Namen mit ”-” beginnen, z.B. ”foo”, verwenden Sie eine der folgenden Anweisungen: > rm -- - foo > rm ./ - foo 7.2.3.5. Das Anzeigen von Dateien Jede Textdatei kann am Bildschirm mit automatischem Scrolling (Befehl cat) oder bildschirmweise (Befehl less, more) ausgegeben werden : Beispiel 7.5 > pwd / mounts / users / student / huber Ausgabe der Datei Fenster am Bildschirm automatisches Scrolling: > cat text . txt bildschirmweise: > more text . txt bildschirmweise, mit verbesserter Positioniermöglichkeit als more: > less text . txt 7.2.3.6. Das Verwalten von Verzeichnissen Innerhalb von Verzeichnissen können beliebige neue Verzeichnisse kreiert (Befehl mkdir) oder, falls sie leer sind, gelöscht (Befehl rmdir) werden. Der Benutzer kann jedes Verzeichnis zu seinem Working Directory machen (Befehl cd). Beispiel 7.6 das momentane Verzeichnis ist : > pwd / mounts / users / student / huber Ein Verzeichnis loesungen soll kreiert werden: > mkdir loesungen Das Working Directory soll auf loesungen gesetzt werden: > cd loesungen Der Benutzer will in sein Home Verzeichnis springen: > cd Relative und absolute Datei- oder Verzeichnisbezeichnungen Linux kann Dateien über relative oder absolute Dateibezeichnungen ansprechen. Während absolute Dateinamen die Dateihierarchie, ausgehend vom Rootdirectory im Namen auflisten, beginnt die Auflistung der Unterverzeichnisse bei relativen Bezeichnungen erst ab dem momentanen Working Directory. 7.2. Verwalten von Dateien Teil 1 103 Beispiel 7.7 > pwd / mounts / users / student / huber absolute Dateibezeichnung: > ls / mounts / users / student / huber / briefe relative Dateibezeichnung: > ls briefe 7.2.3.7. Das Kopieren und Umbenennen von Dateien Unter UNIX kann eine Datei in eine andere kopiert werden (Befehl cp). Dabei werden bestehende Dateien überschrieben. Mehrere Dateien können mit einem cp Befehl nur in Verzeichnisse kopiert werden. Sollen die Namen von Dateien oder Verzeichnissen geändert werden, so gibt es unter UNIX den Befehl mv (=move). Beispiel 7.8 > pwd / mounts / users / student / huber Alle Dateien und alle Unterverzeichnisse aus dem Verzeichnis seminar/ sollen in das Verzeichnis seminar_alt/ kopiert werden: > cp -r seminar seminar_alt Alle Dateien aber keine Unterverzeichnisse aus dem Verzeichnis seminar/ sollen in das Verzeichnis letzte/ kopiert werden: > mkdir letzte > cd seminar > cp * ../ letzte Alle Dateien und alle Unterverzeichnisse aus dem Verzeichnis letzte/ im Verzeichnis seminar/ sollen in das neue Verzeichnis /sicherung kopiert werden: > mkdir ../ sicherung > cp -r ../ letzte / seminare ../ sicherung Das Verzeichnis letzte soll in aller_letzte umbenannt werden: > mv letzte aller_letzte 7.2.4. Dateinamen und der Einsatz von Wildcards 7.2.4.1. Einsatz von Wildcards Um in einem Befehl mehrere Verzeichnisse oder Dateien anzusprechen, können in den Namen Wildcards verwendet werden. Wichtige Wildcards sind * (steht für alles, außer einem Punkt am Anfang der Datei) und ? (steht für einen Buchstaben) Beispiel 7.9 > pwd / mounts / users / student / huber Alle Dateien in allen Verzeichnissen, in deren Namen einf vorkommt, sollen aufgelistet werden : > ls */*/* einf * 104 7. Linux Alle Dateien, die einen sechs Buchstaben langen Namen haben, sollen aufgelistet werden : > ls */*/?????? 7.2.4.2. Verwendung von Sonderzeichen Bestimmte Sonderzeichen in Dateinamen werden von der Shell interpretiert und zur Dateinamengenerierung verwendet. \c Aufheben der Dateinamen Generierung für den nachfolgenden Buchstaben c \ am Ende Eine Zeile fordert eine Folgezeile ”” Aufheben der Dateinamenexpandierung für den eingeschlossenen String tilde (˜) Die bash (Shell) ersetzt die tilde durch das Homedirectory Beispiel 7.10 Ein Dateinname enthät ein Leerzeichen : Kreieren der Datei Mathe V1 > cat > " Mathe V1 " Kreieren und Ansprechen der Datei Mathe* > cat > Mathe \* > ls Mathe \* 7.2.5. Das Wichtigste in Kürze • Das Linux Dateisystem ist ein hierarchisches, baumartiges Dateisystem, bei dem Verzeichnisse Device-übergreifend abgespeichert sein können. Das oberste Verzeichnis heißt root Directory. • In Linux gibt es gewöhnliche Dateien, Verzeichnisse (Directories) und spezielle Dateien (Device Files). Je nach Aufgaben sind sie in Standardverzeichnissen abgespeichert. • Datei und Verzeichnisnamen dürfen 254 Bytes lang sein, Groß- und Kleinbuchstaben werden unterschieden, Wildcards (*,?,\,~) werden unterstützt. • Zu jedem Zeitpunkt befindet sich der User in einem Working Directory, das er mit pwd ausgeben und mit cd ändern kann. • Datei- und Verzeichnisbezeichnungen können absolut (beginnend beim root Directory) und relativ (beginnend beim Working Directory) angegeben werden. • Der User kann Dateien anlegen (Befehl cat), am Terminal anzeigen (Befehl cat), kopieren (Befehl cp), umbenennen (Befehl mv) und löschen (Befehl rm). • Mehrere Dateien können nur in ein Verzeichnis kopiert werden. Verzeichnisse können neu angelegt (Befehl mkdir) und falls falls sie leer sind, können Sie mit dem Befehl rmdir, sonst mit dem Befehl rm -r gelöscht werden. • Beim Kopieren und Umbenennen von Dateien verwaltet Linux keine alten Versionen von Dateien, sondern überschreibt sie. 7.3. Editieren von Texten 105 7.2.6. Tipps für die Praxis 1. Gemeinsame Optionen -i, -r, -f bei Dateioperationen Bei den Befehlen rm, cp und mv haben die Optionen -i, -r und -f die gleiche Funktionalität: -i (interactive), fragt den Benutzer bevor eine Datei überschrieben wird. -r (recursiv) Bei der Dateinamengenerierung werden auch Dateinamen aus den Unterdirectories generiert. -f (force) Keine Nachfragen. 2. Wildcard * und die Option -R beim ls Befehl Wird ''ls *'' aufgerufen, so werden auch die Inhalte aller Unterverzeichnisse ausgegeben. ls -d * listet nur die Namen der Verzeichnisse auf. Die Option -R listet den Inhalt und den Namen aller Verzeichnisse und Unterverzeichnisse auf. 3. More Befehl in Pipes Erzeugt ein Befehl eine Terminalausgabe, die länger als eine Bildschirmseite ist, so kann die Ausgabe, auf den less Befehl „gepiped“, also bildschirmweise ausgegeben werden. ls * | less 4. Automatische Dateinamengenerierung bei Kommanodaufrufen. Bei allen Kommandoaufrufen ist die automatische Dateinamengenerierung der Shell eingeschaltet: cd semin* ist äquivalent zu cd seminar. Die Kommandozeile kann auch durch die Tabulatortaste automatisch vervollständigt werden. cd sem <tab> wird zu cd seminar, falls es nur ein Verzeichnis mit sem beginnend gibt, anderenfalls erscheint nur ein Teilstück bzw. beim zweiten Drücken von <tab> eine Auswahl. 5. Verhindern des automatischen Löschens oder Überschreibens von Dateien Da Linux alte Versionen von Dateien defaultmäßig überschreibt, empfiehlt es sich für die Befehl mv, cp und rm alias Definitionen mit der interactive Option einzuführen. Die alias Definitionen werden mit der Option -f überschrieben. alias alias alias rm cp mv rm -i cp -i mv -i 6. Wildcards bei Verborgenen Dateien Wildcards in einem Dateinamen generieren keinen Dateinamen der mit einem Punkt beginnt (=Verborgene Datei). Abhilfe: ls .* 7.3. Editieren von Texten 7.3.1. Einleitung Unter Linux gibt es mehrere Editoren mit verschiedenen Eigenschaften für unterschiedliche Einsatzgebiete : 106 7. Linux Beispiel 7.11 • vi:Fullscreen Editor, umschaltbar in den ex-Editor-Modus • emacs: wichtiger GNU GPL Editor unter LINUX mit Arbeitsumgebung • kate: ist ein freier Texteditor für Programmierer. Diese drei Editoren haben verschiedene technische Bedingungen für die Nutzung. Der vi läuft in jeder Konsole (Textmodus, xterm). Der emacs kann sowohl in der Konsole laufen mit der Option -nw, als auch im grafischen Modus. Kate dagegen läuft nur im Grafikmodus, genauer mit Hilfe von KDE-Bibliotheken auf X11 aufsetzend. Ein weiteres Beispiel für einen simplen Editor in der Textkonsole ist mcedit. Gedit ist ein weiterer Editor im Grafikmodus. In diesem Kapitel lernen Sie: • Aufrufen von kate • Die Fenster von kate • Die Menüeinträge von kate • Erstellen einer neuen Datei • Spezielle Kommandos zum praktischen Gebrauch Aus dem Handbuch zu kate: http://docs.kde.org/stable/de/kdesdk/kate/fundamentals.html#starting-kate 7.3.2. Aufrufen des kate Editors kate wird vom K-Menü oder von der Befehlszeile aufgerufen. Vom K-Menü Das KDE → Programmmenü wird durch Klicken auf den großen K-Knopf oder das jeweilige Symbol der Linux Version links unten auf dem Bildschirm in der Werkzeugleiste geöffnet. Zeigen Sie mit der Maus auf den Menüpunkt Programme, Dienstprogramme, Editoren. Es erscheint eine Liste der verfügbaren Editoren. Wählen Sie kate (auch aufgeführt als erweiterter Texteditor). kate lädt die zuletzt bearbeiteten Dateien, außer Sie haben eingestellt, dass dies nicht der Fall sein soll. Sehen Sie unter „Einstellungen - kate einrichten“ nach, wie Sie diese Funktion ein- und ausschalten können. Von der Befehlszeile Sie können kate auch von der Befehlszeile starten. Wenn Sie dabei gleichzeitig einen Dateinamen angeben, wird diese Datei durch kate geöffnet oder erzeugt. Verschiedene Modi von kate: Textdatei Mit Hilfe von kate kann man eine Textdatei erstellen indem man beim Speichern oder Erstellen die Endung .txt hinzufügt. 7.3. Editieren von Texten 107 .perl Datei Kate sieht eine Perldatei durch den Header #!/usr/bin/perl, um es übersichtlicher zu machen fügt man beim Speichern noch die Endung .perl dazu. 7.3.2.1. Sitzungen: Sitzungen erlauben Ihnen mehrere Listen von Dokumenten und Einstellungen für das Benutzen in kate zu speichern. Sie können beliebig viele Sitzungen speichern, und Sie können unbenannte oder anonyme Sitzungen für das einmalige Bearbeiten von Dokumenten verwenden. Neue Sitzung: Wenn Sie eine neue Sitzung starten, dann wird das Dialogfenster für die Standardsitzung geöffnet. Zum Speichern der Fenstereinstellungen in der Standardsitzung müssen Sie das Feld „Fenstereinstellungen einbeziehen“ auf der Karte „Sitzungsverwaltung“ unter „Einstellungen - kate einrichten“ einschalten, dann die Standardsitzung laden, die Fenstereinstellungen anpassen und die Sitzung speichern. Letzte Sitzung: Wenn sie auf „Sitzung öffnen“ klicken so wird die alte von Ihnen verwendete Sitzung geöffnet mit allen Fenstern, Verzeichnissen und Dateien mit denen schon gearbeitet wurde. Im Editorbereich erscheint die letzte bearbeitete Datei. Beispiel 7.12: Kate: Öffnen einer bestehenden Datei kate Dateiname . txt kate datei . perl 7.3.2.2. Erstellen einer neuen Datei Es gibt 2 Möglichkeiten mit Hilfe von kate eine Datei zu erstellen: 1. In der Befehlszeile wird der Name einer neuen Datei angegeben: kate neuedatei . perl Die Datei wird im Verzeichnis Documents angelegt. Daher ist es empfehlenswert die zweite Möglichkeit vorzuziehen um alle z.B. Perldateien in einem extra Verzeichnis zur Verfügung zu haben. 2. Kate aufrufen: kate Datei → Neu kate ünterstützt das Drag-and-Drop-Protokoll von KDE. Dateien können gezogen und auf kate abgelegt werden; von der Arbeitsoberfläche, Dolphin, oder einer FTP-Seite, die in einem Dolphin-Fenster geöffnet ist. 108 7. Linux Abbildung 7.3.: Editor: Kate 7.3.2.3. Die Fenster des kate Editors Kate ist in verschiedene Bereiche geteilt : Das Hauptfenster von kate ist ein StandardKDE-Anwendungsfenster mit einer zusätzlichen Seitenleiste, die Werkzeugansichten enthält. Es hat eine Menüleiste mit den Standardmenüs und einigen mehr, sowie eine Werkzeugleiste mit Knöpfen für oft benutzte Befehle. Der wichtigste Teil des Fensters ist der Editorbereich, der standardmäßig einen Texteditor anzeigt, in dem Sie Ihr Dokument bearbeiten können. Die Dokumentenliste zeigt alle aktuell in Kate geöffneten Dateien an. Dateien, die noch nicht gesicherte Änderungen enthalten, werden mit einem kleinen DiskettenSymbol links neben dem Dateinamen gekennzeichnet. Wenn zwei oder mehrere Dateien mit dem selben Namen (in verschiedenen Verzeichnissen) geöffnet sind, wird an die Namen eine Zahl angehängt z. B. ”< 2 >” usw. Für die Auswahl der gewünschten Datei wird ihr Name einschließlich Pfad in der Kurzinfo angezeigt. Wenn Sie ein Dokument aus der Liste aktiv machen wollen, klicken Sie einfach auf den Namen des Dokuments in der Liste. Die Dokumentenliste stellt standardmäßig die Einträge farbig dar: Die Einträge der zuletzt bearbeiteten Dokumente werden mit einer Hintergrundfarbe hervorgehoben, Dokumente, die tatsächlich bearbeitet wurden, werden durch eine zusätzlich eingeblendete Farbe hervorgehoben. Das Dokument, das zuletzt bearbeitet wurde, hat die stärkste Farbe, so dass Sie die Dokumente, an denen Sie aktuell arbeiten, einfach finden können. Diese Hervorhebungen können Sie im Einrichtungsdialog für die Dokumentliste einrichten. Der Dateisystem-Browser ist ein Verzeichnisanzeiger, von dem aus Sie Dateien im aktuell angezeigten Verzeichnis öffnen können. Von oben nach unten besteht der Dateisystem-Browser aus folgenden Elementen: Einer Werkzeugleiste, diese enthält Standardnavigationsknöpfe zum schnellen Wechsel der Verzeichnisse. Die Standardposition der Dokumentliste sowie vom Dateisystem-Browser ist links vom Editorbereich im Kate-Fenster. Der eingebaute Terminal-Emulator ist eine Kopie der KDEAnwendung Konsole, er ist durch Wählen von Fenster → Werkzeugansichten → Terminal 7.3. Editieren von Texten 109 anzuzeigen oder einfach durch Drücken der Taste F7 aufrufbar und bekommt beim Einschalten den Fokus. Wenn die Option „Automatisch mit dem aktuellen Dokument abgleichen“ im Feld „Einstellungen“ von Kate einrichten eingeschaltet ist, wird das Verzeichnis des Terminal-Emulators in das Herkunftsverzeichnis der aktuellen Datei umgeschaltet, wenn dies möglich ist. Die Standardposition ist unten im Kate-Fenster, unterhalb des Editorfensters. 7.3.3. Wichtige Menüeinträge Das Menü Datei • Datei → Neu (Strg+N) Dieser Befehl startet eine neue Datei im Editorfenster. In der Dateiliste links wird die neue Datei als „Unbenannt“ bezeichnet. • Datei → Öffnen (Strg+O) Öffnet das Standard-KDE Dialogfenster, das das Öffnen einer oder mehrerer Dateien erlaubt. • Datei → Zuletzt geöffnete Dateien Dieser Befehl öffnet ein Untermenü mit einer Liste der zuletzt bearbeiteten Dateien. Sie können daraus direkt eine dieser Dateien öffnen. • Datei → Öffnen mit Dieses Untermenü enthält eine Liste mit Anwendungen, die den MIME-Typ des aktuellen Dokumentes verarbeiten können. Das Klicken auf einen Eintrag öffnet das aktuelle Dokument mit dieser Anwendung. Weiterhin gibt es einen Eintrag „Sonstige“. Dieser Befehl öffnet ein Dialogfenster, in dem Sie eine andere Anwendung auswählen können, in der die aktive Datei geöffnet werden soll. Die aktive Datei bleibt weiterhin in Kate geöffnet. • Datei → Speichern (Strg+S) Dieser Befehl speichert Ihre Datei. Benutzen Sie ihn oft. Solange die Datei noch den Namen Unbenannt trägt, wird automatisch anstelle von Speichern der Befehl „Speichern unter“ ausgeführt. • Datei → Speichern unter Mit diesem Befehl benennen Sie Dateien oder benennen diese um. Es wird das Dialogfenster zum Speichern einer Datei aufgerufen. Dieses Dialogfenster funktioniert genauso wie das Dialogfenster zum Öffnen einer Datei. Sie können sich durch das Dateisystem bewegen, eine Vorschau von vorhandenen Dateien ansehen oder Masken zur Dateiauswahl benutzen. Geben Sie den Namen, den Sie der Datei geben wollen, in das Feld ein und klicken Sie auf OK. Achten Sie dabei auch auf die Kodierung. Das Menü Bearbeiten • Bearbeiten → Überschreibmodus (Einfg) Schaltet zwischen den beiden Arten des Eingabemodus um. Wenn der Modus EINF ist, dann setzen Sie die eingegebenen Zeichen an der Stelle des Cursors ein. Wenn der Modus Überschr. ist, dann ersetzt jedes eingegebene Zeichen ein Zeichen rechts vom Cursor. Die Statusleiste zeigt den aktuellen Status des Auswahlmodus an, entweder EINF oder Überschr. 110 7. Linux Das Menü Ansicht • Ansicht → Zeilennummern anzeigen (F11) Mit diesem Eintrag wird ein zusätzlicher Rand an der linken Seite des aktiven Rahmens ein- oder ausgeschaltet, der Zeilennummern anzeigt. Das Menü Extras • Extras → Terminal mit aktuellem Dokument synchronisieren Diese Option bewirkt, dass der eingebaute Terminal-Emulator immer mit cd zum Ordner des aktuellen Dokuments wechselt, wenn ein neues Dokument geöffnet wird oder zu einem anderen Dokument umgeschaltet wird. • Extras → Kodierung Sie können die Standardeinstellung für die Kodierung, die in Einstellungen → Kate einrichten ... Öffnen/Speichern festgelegt ist, für dieses Dokument hier verändern. • Extras → Kommentar Dies fügt das Zeichen für eine Kommentarzeile und ein Leerzeichen an den Zeilenanfang der aktuellen Zeile oder der aktuellen Auswahl hinzu. • Extras → Kommentar entfernen Dies entfernt das Zeichen für eine Kommentarzeile und ein Leerzeichen (sofern vorhanden) am Zeilenanfang der aktuellen Zeile oder der aktuellen Auswahl. • Extras → Großschreibung Der ausgewählte Text oder der Buchstabe nach dem Cursor wird in Großschreibung gesetzt. • Extras → Kleinschreibung Der ausgewählte Text oder der Buchstabe nach dem Cursor wird in Kleinschreibung gesetzt. • Extras → Großschreibung am Wortanfang Setzt den ausgewählten Text oder das aktuelle Wort in Großbuchstaben. 7.3.4. Spezielle Kommandos zum praktischen Gebrauch Strg+Z Abbrechen und Rückgängigmachen eines kate Kommandos. Strg+S Speichern der aktuellen Datei im aktuellen Zustand. Strg+Q Beenden - Aktives Editorfenster schließen. 7.3.5. Andere Editoren SED: Der sed ist ein batchorientierter Editor. Die Editor Kommandos werden in der Aufrufzeile oder in Scriptfiles eingegeben. Der sed arbeitet die Befehle sequentiell ab und schreibt das Ergebnis des Editierens auf das Terminal. Aufruf : sed [ - n ] -f scriptfile [ file - list ] sed -n scriptfile [ file - list ] 7.4. Verwaltung von Dateien Teil 2 111 Beispiel 7.13: sed sed s / abc / def / d test ersetzt den string abc durch den string def in jeder Zeile des Files test sed -f script - file test bearbeitet den File test mit den Kommandos aus script GNU - EMACS: Er ist ein freier (GPL) fullscreen Editor, der für zahlreiche Linux Systeme implementiert ist. Er bietet eine komplexe Arbeitsumgebung zum gleichzeitigen Editieren, Programmerstellen und Arbeiten mit der Shell. Außerdem erlaubt er dem Benutzer, eine eigene Editorumgebung mit LISP ähnlichen Befehlmacros zu erstellen. 7.4. Verwaltung von Dateien Teil 2 7.4.1. Die einzelnen Merkmale einer Datei 7.4.1.1. Die Dateimerkmale im Überblick Der Befehl ls -lisg listet alle Dateimerkmale : Abbildung 7.4.: Dateimerkmale im Überblick 7.4.2. Gruppen und Owner • Jedem Benutzer wird unter Linux in der Datei /etc/passwd eine eindeutige Benutzer(Benutzer ID) und eine Gruppennummer (Gruppen ID) zugeordnet. Der UNIX Befehl id gibt die Benutzer und Gruppeneinstellungen an. > id • In einer Gruppe können mehrere Benutzer zusammengefasst werden. • Unter Linux kann jeder Benutzer Mitglied mehrerer Gruppen sein. • In der Datei /etc/group wird festgelegt, welcher Benutzer zu welcher Gruppe gehört. Außerdem wird in dieser Datei für den Gruppen ID ein symbolischer Name definiert. • Der Loginname ist der symbolische Name für den Benutzer ID. • Benutzer IDs liegen zwischen 0 und 65535, wobei 0 für den Superuser reserviert ist. Die Nummern 1-99 sind ebenfalls reserviert. 112 7. Linux 7.4.2.1. Zugriffsrechte unter Linux Unter Linux werden folgende drei Klassen von Benutzern unterschieden : u : user, gleicher User ID g : group, gleicher Gruppen ID o : beliebiger User - und Gruppen ID Für jede dieser drei Benutzerklassen werden drei verschiedene Arten von Zugriff unterschieden : r : Lesender Zugriff w : Schreibender Zugriff x : Ausführender Zugriff Je nach Art der Datei haben die Zugriffsrechte verschiedene Bedeutungen : Dateiart Gerätedatei Verzeichnis normale Datei read darf vom Gerät lesen auf Dateien darf zugegriffen werden lesen erlaubt write darf auf Gerät schreiben Dateien im Verzeichnis dürfen gelöscht werden ändern erlaubt execute –––– In das Verzeichnis darf mit cd gesprungen werden ausführen erlaubt Tabelle 7.1.: Bedeutungen von Zugriffsrechten Strategie zum Test der Zugriffsrechte bei Dateien Abbildung 7.5.: Zugriffsrechte bei Dateien Ändern der Zugriffsrechte Die Zugriffsrechte einer Datei können mit symbolischen Werten oder mit einer Protectionmaske geändert werden. Ändern mit symbolischen Werten : chmod chmod chmod chmod u g o a <op > <op > <op > <op > rwx rwx rwx rwx dateiname dateiname dateiname dateiname oder oder oder oder Verzeichnisname Verzeichnisname Verzeichnisname Verzeichnisname u : user , g : group , o : other , a : all 7.4. Verwaltung von Dateien Teil 2 <op > ... = <op > ... <op > ... + 113 explizites Setzen des angegebenen Rechts wegnehmen des angegebenen Rechts dazunehmen des angegebenen Rechts Der Befehl lautet (ein Beispiel): chmod a + r test : alle erhalten das Recht zum Lesen chmod ug + wx test : User und Gruppe erhält das Recht zum Schreiben und Ausführen Ändern mit einer Oktalzahl/Maske : Der Befehl lautet: chmod maske dateiname user r w x 0 1 0 1 0 1 4 2 1 erstes Byte group r w x 0 1 0 1 0 1 4 2 1 zweites Byte other r w x 0 1 0 1 0 1 4 2 1 drittes Byte Tabelle 7.2.: Ändern mit einer Oktalzahl/Maske Ein gesetztes Bit bedeutet, dass das Recht für die spezifische Gruppe gesetzt ist. Beispiel 7.14 Es sollen folgende Rechte vergeben werden : user = rw, group = x, other = daraus errechnet sich folgende Maske: user = rw group = x other = - . . . 110 . . . 001 . . . 000 →4·1+2·1+1·0=6 →4·0+2·0+1·1=1 →4·0+2·0+1·0=0 Maske = 610 Der Befehl lautet (ein Beispiel) : > chmod 610 test Einstellen der Defaultmaske Wird eine Datei kreiert, so wird ihr Zugriffschutz nach einem Defaultwert festgelegt. Der Defaultwert kann mit dem Befehl umask gesetzt werden. Ändern der Gruppenzugehörigkeit einer Datei Der Besitzer einer Datei kann, falls er Mitglied dieser Gruppe ist, die Gruppenzugehörigkeit einer Datei ändern. Der Befehl lautet (ein Beispiel): > chgrp student2 test Ändern des Owners einer Datei Nur der Superuser kann den Owner einer Datei ändern. Der Befehl lautet (ein Beispiel) : > chown student test 114 7. Linux 7.4.3. Die Bedeutung von Devicegrenzen 7.4.3.1. Plattenplatzbelegung Jede Plattenpartition entspricht im System einem Device. Damit der Benutzer mit einem Device über eine Dateistruktur arbeiten kann, muss die Partition initialisiert werden, wodurch die Partition als Dateisystem ansprechbar wird. Ein Benutzer kann erst dann mit einem Dateisystem arbeiten, wenn es mit dem mount Befehl in das hierarchische Dateisystem von Linux eingebunden ist. Beim mount Befehl muss der Benutzer das Verzeichnis angeben, in das er das Dateisystem einbindet. Der Befehl lautet (ein Beispiel) : > mount / dev / sdc1 / usr Nachdem das Dateisystem „gemounted“ ist, sind seine Dateien über die hierarchische Dateistruktur zugänglich. Mit dem Befehl cd kann der Benutzer in jedes Verzeichnis springen. Der Befehl df gibt an, welche Dateisysteme in welches Verzeichnis gemounted sind : > df Filesystem node / dev / sda1 / dev / sdb1 / dev / sdc1 Total kbytes 15343 191958 49279 kbytes used 9765 163585 35474 kbytes free 4044 9178 8878 % used 71% 95% 80% Mounted on / / usr / usr / users 7.4.3.2. Der Symbolic Link Unter Linux kann man mit einem Dateinamen auf eine Datei zeigen, die auf einem anderen Device liegt. Die Verbindung zwischen Dateien über die Devicegrenzen hinweg funktioniert nur mit einem symbolic link, innerhalb eines Devices sind auch hard links möglich. Bei einem symbolic link wird im Header der Datei nicht die Inode - Nummer der Datei auf die er zeigt, sondern der komplette Dateinamen, zusammen mit seinem Pfad eingetragen. Der Referenzzähler erhöht sich bei symbolic links nicht. Beispiel 7.15 Die Datei benutzer soll auf das Verzeichnis /usr/users zeigen. Die Datei benutzer darf vorher nicht existieren : > ln -s / usr / users benutzer > ls -l benutzer lrwxr - xr - x 1 kurs 5 Jul 4 15:30 benutzer -> / usr / users 7.4.4. Das Wichtigste in Kürze • Die wichtigsten Dateimerkmale einer Datei sind: Datei Eigentümer und - Gruppe Dateischutz und andere Dateistatistik Größe der Datei in Bytes Blockadresse der Daten der Datei auf der Platte Zeit der Datei - Erzeugung Zeit des letzten lesenden Zugriffs 7.5. UNIX-Befehle 115 Zeit des letzten schreibenden Zugriffs Anzahl der Verweise auf die Datei • Jedem Benutzer unter Linux wird über seinen Benutzernamen ein Benutzer ID und ein Gruppen ID zugeordnet. • Der Benutzer root (Benutzer ID = 0) hat im Linux - System privilegierte Rechte und kann alle Datei- und Systemattribute ändern. • Ein Benutzer kann Mitglied mehrerer Gruppen sein. • Jede Datei gehört einem Benutzer. Über Zugriffsrechte wird geregelt, für was eine Datei verwendet werden kann. • Bei den Zugriffsrechten werden drei Klassen unterschieden : user, group und other. • Für jede Klasse kann man einen read, write oder execute Zugriff festlegen. • Beim Bearbeiten einer Datei prüft Linux zu welcher Klasse der Benutzer, relativ vom Besitzer der Datei gehört: user : gleicher Benutzer ID group : gleicher Gruppen ID other : beliebiger Benutzer oder Gruppen ID. • Die Zugriffsrechte unter Linux können symbolisch oder mit Oktalzahl gesetzt oder geändert werden. • Ein Datenträger wird unter Linux in Partitionen unterteilt, die, falls sie initialisiert sind, ein eigenständiges Dateisystem haben. • Dateisysteme werden in die hierarchische Dateistruktur von Linux eingebunden (gemounted) 7.5. UNIX-Befehle 7.5.1. Hilfe (Befehlsoptionen, Parameter, generelle Verwendungsweise, Verwendungsbeispiele) • man Befehl • info Befehl Aufbau von man und info pages (Auszug): – NAME (Names des Programms) – SYNOPSIS (generelle Struktur des Befehls) – DESCRIPTION (kurze Zusammenfassung, was der Befehl tut) – OPTIONS (Optionen, Parameter und deren Beschreibung) – EXAMPLES (Beispiele zur Verwendung, empfehlenswert!) – SEE ALSO (man pages von ähnlichen Programmen oder config files) • -h oder --help Meist stehen auf beiden Seiten die gleichen Informationen, aber z.B. bei GNU Programmen wird man in den Info Pages eher fündig (manchmal auch umgekehrt). 116 7. Linux 7.5.2. Einsatz der UNIX-Shell: Pipes, >, < (Ausgabeumleitung) > sort liste > sortierte_liste Hier wird die Ausgabe von sort in eine Datei umgeleitet. > ls -l | less Umleitung der Ausgabe von ls in das Programm less. Mehrfachverkettungen mittels Pipe sind auch möglich s.u. > cat File Schreibt ein File in die Standardausgabe (meist das aktuelle Terminal), von der aus es weiterverarbeitet werden kann. > echo String Zeigt den String in STDOUT an > echo $Var Zeigt den Inhalt der Variable Var in STDOUT an > tail -n Zeigt die letzten n Zeilen der Datei an. > head -n Zeigt die ersten n Zeilen der Datei an. 7.5.3. Kommandooptionen Welche Kommandooptionen: cmd -- help -s value # kurze Variante -- size = value # lange Variante 7.5.4. Shells: bash, tcsh piping | redirecting > >> < << &1 &2 Control zur Steuerung von Prozessen: ^C ^S ^Q ^Z Abbruch Anhalten der Ausgabe aufs Terminal resume der Ausgabe aufs Terminal schicke Prozess in den Hintergrund : neue Befehle z . B . bg oder fg damit er weiter läuft , können eingegeben werden 7.5.5. Was ist los auf dem Rechner? > top > ps listet eigene Prozesse auf > ps - ef listet alle Prozesse am System auf > ps - ef | grep bzip 7.5. UNIX-Befehle 117 listet alle Prozesse mit dem Namen bzip auf > kill -9 PID ( Prozess Identification ) Wichtig ist die LOAD des Rechners. Etwas im Hintergrund arbeiten lassen: Am Ende des Befehls ein & Zeichen: bzip wiki.dump & 7.5.6. Wegwerfen der Ausgabe einer Datei > / dev / null Metazeichen der SHELL um Dinge zu demaskieren: ' (umklammern mit Hochkomma ) \ (Backslash vor einzelnen Sonderzeichen Beispiele: \<ret> Verlängerungszeichen einer Zeile \<space> Leerzeichen in Dateinamen 7.5.7. Archive anlegen Behält die Direktory Struktur, Zeit, Owner und die Zugriffsrechte tar - cf archiv . tar file1 file2 file2 ... oder tar - cf archiv . tar dir1 dir2 ? 7.5.8. Komprimieren von Dateien zip - unzip gzip - gunzip gunzip -c ( zcat ) bzip2 - bunzip2 bzcat 7z . zip . gz . bz2 .7 z 7.5.9. Archivieren mit Komprimieren tar - zcvf archiv . tgz file1 file2 file2 ... oder tar - zcvf archiv . tgz dir1 dir2 ... Entpacken: tar - zxvf archiv . tgz Auflisten des Inhalts eines Archivs tar - tf archiv . tar 7.5.10. Finden von Dateien und ausführen eines Befehls find zum Extrahieren aller Files eines Verzeichnisbaums und Anwenden eines Befehls > find . - name "*. txt " - print > find . - name "*. txt " - exec bzcat '{} ' \; | lynx - stdin - dump - display_charset = utf8 > find . - name "*. txt " | xargs bzcat 118 7. Linux 7.5.11. Finden von Unterschieden in Dateien > cmp Vergleicht zwei Dateien Byte für Byte > diff Vergleicht zwei Dateien Zeile für Zeile > diff3 Vergleicht zwei Dateien Byte für Byte 7.5.12. UNIX: Tokenisierung, Sortieren, Frequenzlisten Tokenisierung • tr • grep -o • egrep -o • perl 7.5.13. Translate von Zeichen Achtung: bisher (Stand 2010) bietet UNIX beim Befehl tr keine utf8 Unterstützung. > tr -d a < sz . txt löscht alle „a“ aus dem Text > tr -d a < sz . txt löscht alle „a“ aus dem Text > tr " " "\ n " löscht alle Spaces und ersetzt sie mit einem Newline > tr -C -d [a - m ] < sz . txt > tr [a - z ] [A - Z ] < sz . txt > tr -s " " "\ n " < sz . txt ersetzt alle wiederholten spaces aus dem Text 7.5.14. Sortieren-einer-wortliste UNIX Befehl sort • lexikalisch (sort ohne parameter) • nummerisch (sort -n) • aufsteigend (ohne Parameter). absteigend (sort -r) • nach Feldern > tr -s " " "\ n " < sz . txt | sort -f # ignoriert Groß / Kleinschreibung > sort -n # numeric sort > sort -f -S 20 M sz_utf8 . txt # mit großem Buffer ### SIZE may be followed by the following multiplicative suffixes : % 1% ### of memory , b 1 , K 1024 ( default ) , and so on for M , G , T , P , E , Z , Y 7.5. UNIX-Befehle 119 7.5.15. Report und Unterdrücken von Zeilen > uniq -c report or omit repeated lines > uniq -c zählt die Wiederholungszeilen und schreibt die Anzahl davor > sort -n numerischer sort > sort - rn numerischer reverse sort > sort -k 2 > sort -- key =2 sortieren nach Keys (Feld, welches als Sortierschlüssel dient; wenn nicht angegeben wird gesamte Zeile verwendet) 7.5.16. Erzeugen einer Wortliste > tr -s " " "\ n " < sz_txt . txt | sort | uniq -c | sort - nr | less oder : > cat sz_txt . txt | tr " " "\ n "| sort -f | uniq - ic | sort -n > ausgabedatei Die Befehle einzeln: > cat sz_txt . txt Schreibt die Datei nach STDOUT (Standardausgabe), dort wird sie von der Pipe weitergeleitet. > tr " " "\ n " Übersetzt Leerzeichen in newlines. > sort -f Ignoriert Groß- und Kleinschreibung für die Sortierung. > uniq - ic -c zählt die einzelnen Tokenvorkommen. -i zählt groß- und kleingeschriebene Vorkommen zusammen. > sort -n Sortiert nummerisch (nach dem Ergebnis von uniq) > ausgabedatei Leitet in Ausgabedatei um. 174 153 125 118 100 84 57 56 54 49 49 48 46 die der und Linux von zu in für mit den auch eine 120 7. Linux ? usw .. 13 werden . 13 über (...) Bei diesem Ergebnis handelt es sich um eine einfache Frequenzliste, die noch nicht um newlines, Kommata, Anführungszeichen, etc. bereinigt wurde. Dazu empfiehlt es sich, ein Tool zur Behandlung regulärer Ausdrücke zu verwenden (s.u.). 7.6. Automatisieren von Befehlsfolgen mit der Shell 7.6.1. Was ist ein Shellscript Eine Datei, die Shell Kommandos enthält, nennt man Shell Script. In einem Shellscript kann man Linux Befehle, eigene Programme oder andere Shellscripts aufrufen. Über Ablaufsteuerungsanweisungen, Abfragen und Ausgaben an den Benutzer und den Einsatz von Variablen kann man die Reihenfolge und den Inhalt der aufgerufenen Befehle steuern. Ein Shellscript wird für eine bestimmte Shell konzipiert (Bourne Shellscript, C-Shellscript, Korn-Shellscript), da sich danach Befehle und Mechanismen richten, die verwendet werden können. Alle Linux System Shellscripts sind Bourne Shellscripts. Ein Shellscript wird mit dem Namen gestartet und von einer bestimmten Shell sequentiell interpretiert. 7.6.2. Benutzung von Shellscripts • komplizierte, sich öfter wiederholende Befehlsfolgen können vereinfacht und so automatisiert werden (Programmerstellung) • für Systemaufgaben, wie login-Vorgang, Backup, Hochfahren des Systems. • Die zahlreichen Testmöglichkeiten unter Linux einzusetzen damit bei Kommandofolgen keine Fehler passieren. • Für Anfänger erleichtern Scripts komplizierte Befehle. 7.6.3. Das Wichtigste in Kürze • Shellscripts sind in einer Datei zusammengefasste Befehle für eine spezifische Shell • Es gibt verschiedene Shellscripts • In Shellscripts kann man Kommentare eintragen, Variablen einsetzen, vom Benutzer Eingaben fordern, Text ausgeben, und mit Kontrollstrukturen arbeiten. • Die System Shellscripts sind für die Bourne Shell geschrieben. • Für die Bourne Shell gibt es folgende Kontrollstrukturen: if then φ if then else φ if then elif φ for in do done 7.7. Drucken 121 while do done until do done case in esac 7.7. Drucken 7.7.1. CUPS CUPS, auch für Common Linux Printing System - heute oft das Standarddrucksystem. Die folgenden Befehle sind eher historisch, aus Kompatibilitätsgründen aber in jedem System vorhanden. 7.7.1.1. Druckaufträge erzeugen (klassisch) lpr text . txt 7.7.1.2. Das Anzeigen von Druckjobs Zum Ausgeben von Information über den aktuellen Zustand der Drucker, die an das System angeschlossen sind und über den Zustand des Druckauftrags gibt es den Befehl: lpstat Falls ein eigener Druckjob gestartet ist. bzw. lpstat -t was die gesamte Information über alle Queues und Drucker am System ausgibt. lpq ist eine weitere Möglichkeit der Abrage. Zur Verwaltung von Druckern gibt es ein spezielles Drucker-Kontroll-Programm lpc. Es erlaubt den Druckerstatus auszugeben und zu ändern. 7.7.1.3. Das Löschen von Druckjobs Jeder Benutzer kann seinen eigenen, der Superuser beliebige Druckaufträge über die Auftragsnummer stoppen : lprm auftragsnummer 7.7.1.4. Das Wichtigste in Kürze Drucker werden über spezielle Programme, sogenannte Druckerdämons verwaltet. Die Aufgabe des Druckerdämons ist, nur einen Druckauftrag an einem Drucker zu einem Zeitpunkt zuzulassen. Der Systemverwalter definiert für jeden Drucker eine Warteschlange. Der Benutzer wählt beim Druckbefehl die Warteschlange und somit den Drucker. Nachdem der Benutzer den Druckbefehl abgeschickt hat, wird die zu druckende Datei mit den Druckinformationen in das systemweite spool-Verzeichnis kopiert und wenn der Drucker frei ist, vom Druckerdämon zum Drucker geschickt. Information über den Drucker und die Druckaufträge bekommt man mit dem Befehl lpstat -t. 122 7. Linux Jeder Benutzer kann seinen Auftrag über die Auftragsnummer mit dem Befehl lprm löschen. Des Printer-Kontroll-Programm lpc erlaubt Drucker anzuhalten und neuzustarten. 7.8. Linux-Befehle – eine kurze Übersicht 7.8.1. Dokumentation, Dateien, Pfade Befehl wichtige Optionen Beispiel Beschreibung man, info, whatis, apropos cd man ls, info ls Hilfe zu einem Befehl (manual) cd /tmp pwd pwd wechselt in das genannte Verzeichnis (change directory) pwd gibt das aktuelle Verzeichnis aus (print working directory) gibt den Inhalt eines Verzeichnisses (bei -R auch Unterverzeichnisse) aus (list); -l: langes Format, -a: auch versteckte Dateien kopiert Dateien (copy); -R mit Unterverzeichnissen; -a Archiv-Modus (u.a. Unterverzeichnisse samt Inhalt mit kopieren); -i Interaktive Mode, fragt nach vor eventuellem Überschreiben verschiebt Dateien oder benennt um (move); -i (interactive): vor dem Überschreiben von Dateien rückfragen legt datei an löscht Dateien (remove); -f(force) Löschen erzwingen; -r (rekursiv): Verzeichnis samt Inhalt löschen (gefährlich!) Verzeichnis anlegen (make directory); -p (parents): Verzeichnisbaum anlegen Verzeichnis löschen (remove direcotry); -p (parents): Verzeichnisbaum löschen, wenn leer harten Link anlegen; -s: symbolischen Link anlegen Lese-(r), Schreib-(w) und Ausführrecht (x) für Besitzer (u), Gruppe (g), Rest der Welt (o) und/oder alle (a) hinzufügen(+), wegnehmen (-) oder exakt setzen (=) Ändert die Gruppenzugehörigkeit einer Datei; im Beispiel wird datei der Gruppe users zugeordnet. Ändert die Eigentümer einer Datei; im Beispiel wird datei dem Benutzer root zugeordnet zeigt ACL-Zugriffsrechte von datei an ls -l -a -R ls -l /tmp cp -a -R -i cp quelle ziel mv -i mv quelle ziel touch rm -f -r touch datei rm datei mkdir -p rmdir -p mkdir -p newdir/ newsub rmdir verzeichnis ln -s ln -s original link chmod [ugoa][+=][rwx] chmod go-rwx datei chgrp chgrp users datei chown chown root datei getfacl getfacl datei 7.8. Linux-Befehle – eine kurze Übersicht setfacl -m -x setfacl -m u:user:r datei getfattr setfattr getfattr -d -m ’-’ datei setfattr datei 123 setzt ACL-Zugriffsrechte von datei; im Beispiel wird dem Login user Leserechte(r) auf datei gegeben; -m: Rechte setzen; -x: Rechte löschen zeigt erweiterte Attribute von datei an setzt erweiterte Attribute von datei Tabelle 7.3.: Linux-Befehle: Dokumentation, Dateien, Pfade 7.8.2. Textverarbeitung Befehl Beispiel Beschreibung cat wichtige Optionen -n cat datei head, tail -n head -n 100 datei wc -c -m -l -w wc -l datei more, less -S less -S datei sort -r -n sort datei grep -i -l -v -r grep -i regexp datei(en) agrep -Abstand agrep -2 ”hallo” datei Dateiinhalt ausgeben (concatenate); -n Zeilen numerieren gibt die ersten/letzten 100 Zeilen von datei aus. tail -f fortlaufend gibt die Anzahl der Bytes (-c), Zeichen (-m), Zeilen (-l) oder Wörter (-w) von datei aus. zeigt eine Datei seitenweise an; -S: Zeilen nicht umbrechen (nur less) sortiert eine Datei; -r: rückwärts sortieren; n numerisch sortieren durchsucht datei(en) nach einem regulären Ausdruck und gibt passende Zeilen aus; -i (ignore case) Groß/Kleinschreibung ignorieren, -l (list): lediglich Dateien mit Treffern anzeigen; -v: (invert match): nur nicht-passende Zeilen ausgeben; -r: alle Dateien unter einem Verzeichnis rekursiv durchsuchen Findet ”hallo” oder ähnliche Schreibweisen in datei. Über -Abstand wird der Levenshtein-Abstand eingestellt. Zeichen ersetzen. Im Beispiel wird jedes ”a”, das von stdin gelesen wird, durch ”b” ersetzt. ersetzt regulären Ausdruck durch Replacement Löscht alle doppelten Zeilen in datei1 und schreibt das Ergebnis nach datei2 ; -c: Anzahl der Vorkommen angeben vergleicht 2 Dateien (difference); -r: Verzeichnisse rekursiv vergleichen extrahiert spaltenweise Ausschnitte aus Textzeilen; -d: Angabe der Trennzeichen; -f: Angabe der zu extrahierenden Felder verknüpft Zeilen mit identischen Feldern; -e: ersetzt fehlende Felder durch festgelegte Zeichenkette tr tr ”a” ”b” sed s sed s/regexp/replace/ uniq -c uniq -c datei1 datei2 diff -r -y diff alt neu cut -d -f cut -d “,“ -f1 datei join -e join first last Tabelle 7.4.: Linux-Befehle: Textverarbeitung 124 7. Linux 7.8.3. Komprimieren von Dateien/ Ordnern Befehl wichtige Optionen [t|x|c][j|z]f Beispiel Beschreibung tar xvjf datei.tar.bz2 gunzip, gzip, zcat -l gunzip -l datei.gz unzip, zip -l unzip datei.zip bzip2 7za x bzip2 datei 7za x datei.7z split -b=650m split -b=650m datei .tar.bz2-Archiv anzeigen (test), auspacken (extract) oder anlegen (create) (tape archiver). z bei gzipkomprimierten Dateien (.tgz oder .tar.gz), j bei bzip2-komprimierten Dateien (.tbz oder .tar.bz2) .gz-Datei auspacken oder Inhalt auflisten (-l); gzip: Datei packen; zcat Datei packen und auf stdout schreiben .zip-Datei auspacken oder Inhalt auflisten (-l); zip: zip-Datei packen Packt datei nach datei.bz2 Entpackt Dateien aus dem Archiv datei.7z Teilt datei in mehrere 650 MB große Stücke, zusammensetzen mit cat tar Tabelle 7.5.: Linux-Befehle: Komprimieren 7.8.4. Dateisystem Befehl wichtige Optionen Beispiel Beschreibung locate locate *.pl find find -name ”foo*” mount/umount mount /dev/sdb1 /mnt/sdb1 gvfs-mount -d /dev/sdb1 Dateien lokalisieren (benötigt regelmäßige Läufe von updatedb), hier werden alle Dateien mit Endung .pl angezeigt aktuelles Verzeichnis und Unterverzeichnisse nach Dateien durchsuchen, deren Name auf ein Muster passt Laufwerk einbinden/aushängen (mit Root-Rechten) bindet Laufwerke mittels Gnome Virtual File System (GVFS) ein (ohne Root-Rechte) zeigt den durch die Dateien eines Verzeichnisses und seine Unterverzeichnisse belegten Platz an (disk usage); -s (summary): lediglich Gesamtwert, nicht jedes einzelne Unterverzeichnis ausgeben; -h: sinnvolle Größenangabe Zeigt die Belegung der gemounteten Laufwerke an; -h: sinnvolle Größenangabe gvfs-mount du -s -h du -s ./ df -h df -h Tabelle 7.6.: Linux-Befehle: Dateisystem 7.8. Linux-Befehle – eine kurze Übersicht 125 7.8.5. Prozessmanagement und User Befehl su wichtige Optionen - sudo Beispiel Beschreibung su - kennung Shell mit anderer Benutzerkennung starten (root, wenn kein Benutzer genannt ist); -: Login-Shell starten Program mit root-Rechten ausführen (super user do) Prozessliste anzeigen (processes), zeigt PIDs zu Prozessen an Signal an den Prozess mit der ProzessID PID schicken, Standard: SIGTERM (termination); -9: SIGKILLSignal schicken Prozess über seinen Namen beenden Startet befehl mit Priorität 10. Je kleiner die Zahl desto größer die Priorität, 0 normale, -20 höchste, 19 niedrigste Priorität. Setzt für PID die Priorität prio, prio ∈ [-19,20] zeigt eine selbstaktualisierende Tabelle mit Prozessinformationen an(q für quit) setzt den Prozess %1 fort (%1 ist die Nummer des Prozesses, der mit Strg+Z unterbrochen wurde) Benutzer anzeigen, die zuletzt auf diesem Rechner waren. anzeigen wer eingeloggt ist (who). w zeigt zusätzlich Informationen über laufende Prozesse an, finger zeigt Kontaktinformationen über einen Benutzer an sudo /sbin/halt ps aux ps aux kill -9 -l kill PID killall nice -9 -n killall find nice -n 10 befehl renice renice prio PID top top bg, fg bg %1 last who, w, finger -a -i last -a -i finger login Tabelle 7.7.: Linux-Befehle: Prozessmanagement und User 126 7. Linux 7.8.6. Zeichensätze Befehl Beispiel Beschreibung recode wichtige Optionen -l recode latin-1..utf-8 iconv -l -f -t uniconv -decode encode -l iconv -f l1 -t utf8 text.txt uniconv -decode utf-8 encode German locale -a locale file -i file datei.txt Konvertiert eine Datei zwischen verschiedenen Speicherformaten Konvertiert eine Datei zwischen verschiedenen Speicherformaten Liest Zeichen von stdin und schreibt nach Beendigung der Eingabe die Zeichen auf stdout wobei die Umlaute durch ihre Umschreibung ersetzt wurden. zeigt landesspezifische Umgebungsvariablen an Dateityp erraten; -i: Mime Typ ausgeben zeigt Daten byteweise in oktaler oder hexadezimaler Form an hexdump, od hexdump -C UTF-8demo.utf | less Tabelle 7.8.: Linux-Befehle: Zeichensätze 7.8.7. Umgebungsvariablen Befehl wichtige Optionen export set unset setenv echo Beispiel export LANG ”de_DE@euro” -n echo ”$PATH” Beschreibung = setzt Variablen, zeigt ohne Argumente alle Umgebungsvariablen an zeigt Umgebungsvariablen an löscht Umgebungsvariable wie export für andere Shells Variable ausgeben; -n (newline): kein Zeilenvorschub nach Ausgabe Tabelle 7.9.: Linux-Befehle: Umgebungsvariablen 7.8.8. Netzwerkeigenschaften Befehl ss ping ip address ip -6 route wichtige Optionen -p Beispiel Beschreibung ss -p zeigt Informationen über das Netzwerk an; -p: Anzeige der dazugehörigen Prozesse Server anpingen (ohne Option -c mit ctrl+c abbrechen) Anzeige der IP Adresse Anzeige der IP-Routen (-6 für IPv6Routen) ping6 www.lrz.de Tabelle 7.10.: Linux-Befehle: Netzwerkeigenschaften 7.8. Linux-Befehle – eine kurze Übersicht 127 7.8.9. Via Internet Dateien kopieren/ Rechner fernsteuern Befehl wget wichtige Optionen -p -r -l curl -O ssh -X scp rsync -a –delete -n sftp rdesktop vncviewer Beispiel Beschreibung wget -p http://www.lmu.de Internetseite auf Festplatte kopieren; -p: alle zur Darstellung der Seite relevanten Dateien mitladen; -r: Seite rekursiv laden; -l: Rekursionstiefe begrenzen curl http://www.lmu.de Internetseite auf Terminal anzeigen; -O: schreibt Output in Datei ssh -X [email protected]. ssh-Verbindung zu Server aufbauen ifi.lmu.de scp [email protected]. Kopiert die Datei datei von der Uni ifi.lmu.de:datei ziel an die Stelle ziel rsync rsync -av LocalDir/ [email protected]:/RemoteDir/ sftp [email protected]. sftp-Verbindung zu Server aufbauen lan rdesktop -g 80% baut Remote-Desktop-Verbindung auf remote.cip.ifi.lmu.de vncviewer Zugriff auf entfernten Rechner/ vnc.cis.lmu.de:1 Virtual Network Computing Tabelle 7.11.: Linux-Befehle: Rechner fernsteuern 7.8.10. Operatoren zur Ausgabe-/Eingabeumleitung Befehl wichtige Optionen < > 2> » | `` Beispiel Beschreibung tr -s “a“ < datei ls > datei.txt befehl 2>&1 ls » datei.txt cat sz.txt | less stdin umleiten stdout umleiten stderr umleiten stdout an Datei anhängen an Prozess weiterleiten mit Ergebnis des Programmaufrufs weiterarbeiten (`Befehl`) liest von stdin und schreibt zu stdout und Dateien tee Tabelle 7.12.: Linux-Befehle: Operatoren 7.8.11. Versionsverwaltung Befehl svn git wichtige Optionen co ci add up Beispiel Beschreibung svn co add push pull git pull Dateien mittels svn runterladen (co,up), hochladen (ci) oder zum Repository hinzufügen (add). Dateien mittels git runterladen (pull), hochladen (push) oder zum Repository hinzufügen (add). Tabelle 7.13.: Linux-Befehle: Versionsverwaltung 128 7. Linux 7.8.12. Sonstiges Befehl screen wichtige Optionen -r lpr, lprm, lpq crontab Beispiel Beschreibung screen befehl; screen -v parkt aktive Sessions, wichtige Tastenkombination: ctrl+A, D, C, A lpr druckt datei auf einem Drucker; lprm löscht Druckjobs, lpq zeigt Druckjobs an Crontab bearbeiten (-e), anzeigen (-l), oder löschen (-r) Befehl zu bestimmten Zeitpunkt ausführen Terminal wiederherstellen brennt iso.images -o erzeugt CD/DVD image-Datei lpr datei -e -l -r crontab -e at, atrm, atq echo ”reboot” | at 5:00 clear, reset cdrecord, wodim reset wodim dev=/dev/dvd image.iso genisoimage image.iso pfad which rm mkisofs, genisoimage which -J -r -o kompletten Pfad eines Programmes in $PATH ausgeben Tabelle 7.14.: Linux-Befehle: Sonstiges Literaturverzeichnis [H.-94] H.-P. Gumm, M. Sommer: Einführung in die Informatik, Addison-Wesley, Bonn. 579 S., 359 Abb., Hardcover (1994) (Zitiert auf Seite 1) [Kla90] Klaeren, Herbert: Vom Problem zum Programm (1990) (Zitiert auf Seite 1) [LW00] Larry Wall, Jon Orwant, Tom Christiansen: Programming Perl, Third Edition, O’Reilly Media (2000) (Zitiert auf Seiten 11 and 12) [TP01] Tom Phoenix, Randal L. Schwartz: Learning Perl, Third Edition, O’Reilly Media (2001) (Zitiert auf Seite 12) 129 Abbildungsverzeichnis 2.1. Editor:Kate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 7.1. 7.2. 7.3. 7.4. 7.5. Graphische Darstellung des LINUX-Systems Hierarchische Dateistruktur von LINUX . . Editor: Kate . . . . . . . . . . . . . . . . . . Dateimerkmale im Überblick . . . . . . . . Zugriffsrechte bei Dateien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 100 108 111 112 A.1. A.2. A.3. A.4. A.5. A.6. compond-statement . expression-statement if-statement . . . . . while-statement . . . for-statement . . . . do-statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 133 133 133 133 134 130 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tabellenverzeichnis 1.1. Die Rechnergenerationen bis ca. 1990 im Überblick . . . . . . . . . . . . . . . . . . 2.1. Elemente in einer Liste . . . . . . . . . . . . . . . . . 2.2. Logische Operatoren . . . . . . . . . . . . . . . . . . 2.3. Logische Aussagen . . . . . . . . . . . . . . . . . . . 2.4. Vergleichsoperatoren . . . . . . . . . . . . . . . . . . 2.5. Wahre Werte in einem logischen Ausdruck . . . . . . 2.6. Falsche Werte in einem logischen Ausdruck . . . . . 2.7. Zeichencodierung: ASCII, für Buchstaben, mit 7 Bit 2.8. Bedeutung der Steuerzeichen . . . . . . . . . . . . . 2.9. Definitionen des ISO-Latin-1 Character Set . . . . . 2.10. ISO Codierung . . . . . . . . . . . . . . . . . . . . . 2.11. UNICODE Codierung . . . . . . . . . . . . . . . . . 2.12. Die UTF Kodierung im Detail . . . . . . . . . . . . . 2.13. Hash: Zugriff und sort Anweisungen . . . . . . . . . . . . . . . . . . . . . . 16 24 24 25 26 26 39 40 42 43 43 45 55 3.1. Buchstabenklassen ohne UNICODE . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2. Buchstabenklassen mit UNICODE . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 61 7.1. Bedeutungen von Zugriffsrechten . . . . . . . . 7.2. Ändern mit einer Oktalzahl/Maske . . . . . . . 7.3. Linux-Befehle: Dokumentation, Dateien, Pfade 7.4. Linux-Befehle: Textverarbeitung . . . . . . . . 7.5. Linux-Befehle: Komprimieren . . . . . . . . . . 7.6. Linux-Befehle: Dateisystem . . . . . . . . . . . 7.7. Linux-Befehle: Prozessmanagement und User . 7.8. Linux-Befehle: Zeichensätze . . . . . . . . . . . 7.9. Linux-Befehle: Umgebungsvariablen . . . . . . 7.10. Linux-Befehle: Netzwerkeigenschaften . . . . . 7.11. Linux-Befehle: Rechner fernsteuern . . . . . . . 7.12. Linux-Befehle: Operatoren . . . . . . . . . . . . 7.13. Linux-Befehle: Versionsverwaltung . . . . . . . 7.14. Linux-Befehle: Sonstiges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 113 123 123 124 124 125 126 126 126 127 127 127 128 131 A. Anhang A.1. Die Backus-Naur-Form (BNF) Die Backus-Naur-Form wurde zum ersten Mal bei der Defintion von Algol 60 verwendet. Ein Programm besteht aus speziellen Wortsymbolen wie for, if usw., sogenannten terminalen Symbolen. Die terminalen Symbole werden zu komplexeren Gebilden kombiniert, die dann das eigentliche Programm ergeben. Jedes Gebilde nennt man syntaktische Kategorie oder nicht-terminales Symbol der Sprache. Die Syntaxdefinition einer Sprache legt fest, wie diese terminalen und nichtterminalen Symbole kombiniert werden dürfen. Dazu gibt es eine Menge von Produktionen. Die Syntax einer Sprache ist die Menge aller Terminalsymbole, syntakischen Kategorien und Menge der Produktionen. Die BNF besteht aus • Terminalsymbolen: festen Namen, Konstanten • Nichtterminalen Symbolen: eingeschlossen in „< “und „> “ • Metasymbolen – ::= entspricht, kann ersetzt werden: z.B. <Zahl>:: = 1 – | oder z.B. <Zahl>:: = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 – {} Wiederholung: Nullmal oder mehrmal: z.B. <Variablenname>:: = <Buchstabe> { <Ziffer> | <Buchstabe> } Bemerkung: manchmal werden den geschweiften Klammern * oder + hochgestellt, das bedeutet:bei *: die Wiederholung der eingeschlossenen Elemente kann auch Nullmal sein. bei +: Die Wiederholung der eingeschlossenen Elemente muß mindestens einmal sein. Beispiel: Teile der Definition von PERL in BNF • compound-statement compound - statement ::= '{ ' < statement - list > '} ' statement - list ::= < empty > ::= < statement > ::= < statement > < statement - list > Abbildung A.1.: compond-statement 132 A.1. Die Backus-Naur-Form (BNF) – expression-statement-statement expression - statement ::= < expression > '; ' Abbildung A.2.: expression-statement – if-statement if - statement ::= 'if ' '( ' < expression > ') ' < compound - statement > ::= < simple - statement > 'if ' < expression > Abbildung A.3.: if-statement – while-statement while - statement ::= ' while ' '( ' < expression > ') ' < compound - statement > ::= < simple - statement > ' while ' < expression > Abbildung A.4.: while-statement – for-statement for - statement ::= 'for ' '( ' <for - initialization > '; ' <for - control > '; ' <for - iteration > ') ' < statement > for - initialization ::= < empty > ::= < expression > for - control ::= < empty > ::= < expression > for - iteration ::= < empty > ::= < expression > Abbildung A.5.: for-statement 133 134 A. Anhang – do-statement do - statement ::= 'do ' < statement > ' while ' '( ' < expression > ') ' '; ' Abbildung A.6.: do-statement Index Ablaufsteuerungsanweisungen do until, 31 do while, 31 foreach, 32 for, 32 if...else, 28 while, 29 if, 28 Ausdrücke, 18 Arithmetische Ausdrücke, 18 Logische Ausdrücke, 23–24 Wahrheitswerttabelle, 24 Block, 27 Datei einlesen STDIN, 20 close, 34 open, 34 Dateinhandle, 34 Diamondoperator, 34 Filepositionmarker, 35 Datei schreiben, 35 STDOUT, 20 Datenstrukturen, 15 Hashes, 53–55 key, 53 Neues Element einfuegen, 54 sort, 54 value, 53 Zugriff auf Elemente eines Hashes, 53 Liste, 15 Zugriff auf Elemente einer Liste, 16 Skalar, 15 Der Dateibaum im LINUX, 99 Der Symbolic Link, 114 Fachbegriffliche Abkürzungen, 10 Formatierungskonvention, 17, 19, 27, 28, 31, 66 Interne Repräsentation von Zahlen Binärsystem, 36–37 Dezimalsystem, 36 Hexadezimalsystem, 37 Konvention für Dateinamen, 104 Man bzw. info pages bei Linux, 115 Operatoren, 23 Arithmetische Operatoren, 23 modulo, 23 string Operatoren, 23 Konkatenationsoperator, 23 Vervielfältigungsoperator, 23 Vergleichsoperatoren, 24 Vergleichsoperatoren bei Strings, 24 eq, 24 le, 24 lt, 24 ne, 24 qe, 24 qt, 24 Piping bzw. redirecting, 116 Programmaufbau, 12–13 ident line, 12 use strict, 17 Programm editieren, 13 Editor, 13 Programm starten, 13 Programmaufruf, 13 Reguläre Ausdrücke, 57–65 Ausschalten der Metazeichen, 59 Binding Operator, 57 Buchstabenklassen mit UNICODE, 60 Buchstabenklassen ohne UNICODE, 60 Definition, 57 globales Suchen, 62 Greedy-Nongreedy Verhalten, 63 Gruppierung, 61 Metazeichen, 57 Anfang der Zeile, 59 Buchstabenbereich, 58 Ende der Zeile, 59 negierte Buchstabenbereiche, 60 Quantifizierung, 58 Wildcard, 58 Zeichengruppierung, 59 substitute, 63 Relative und absolute Datei- oder Verzeichnisbezeichnu Shellscript, 120 Subroutinen, 73 Übergabe des Argumentwerts, 77 Übergabemechanismus im Detail, 83 Datenaustausch, 74 Definition, 74 Gültigkeitsbereich von Variablen, 77 Iterativ, 83 Lokale Variablen, 76 my, 76 135 136 Index Rekursion, 82 Probleme, 78 Wochenttagsprogramm, 85 Systemroutinen, 66 chomp, 21 chr, 68 join, 69 length, 68 ord, 67 pop, 69 push, 70 reverse, 71 scalar, 68 sort, 72 split, 66 unshift, 71 Texte Editieren mit Kate im LINUX, 105 Tokenisierung, Sortieren, Frequenzlisten mit LiNUX-Befehle, 118–120 Translate von Zeichen mit LiNUX-Befehle, 118 UNICODE Escape-Sequenz, 61 Variable, 16 $_, 51 @_ , 84 Deklaration, 17 Globale Variablen, 82 our, 82 Initialisierung, 18 Wertzuweisung, 19 Variablen Skalar, 57 Verwaltung von Dateien im LINUX Archive anlegen, 117 Das Anlegen von Dateien, 100 Das Anzeigen von Dateien, 102 Das Anzeigen von Inhaltsverzeichnissen, 101 Das Kopieren und Umbenennen von Dateien, 103 Das Löschen von Dateien, 101 Das Verwalten von Verzeichnisse, 102 Finden von Unterschieden in Dateien, 118 Komprimieren von Dateien, 117 Zeichenkodierung -C, 49 binmode, 49 use locale, 47 use open utf8, 50 use utf8, 46 ASCII, 39 ISO Latin-1, 40–43 UNICODE, 43–44 UTF-8, 44–46 Zugriffsrechte unter Linux, 112–113 Index 137