learnxinyminutes-docs/de/tcl.md

472 lines
15 KiB
Markdown
Raw Normal View History

---
contributors:
- ["Poor Yorick", "http://pooryorick.com/"]
translators:
- ["Martin Schimandl", "https://github.com/Git-Jiro"]
filename: learntcl-de.tcl
---
Tcl wurde kreiert von [John Ousterhout](http://wiki.tcl.tk/John Ousterout) als
2024-05-12 10:15:38 +00:00
eine wiederverwendbare Scriptsprache für Chip-Design Werkzeuge die er kreiert
hat. Im Jahre 1997 wurde er mit dem [ACM Software System
Award](http://en.wikipedia.org/wiki/ACM_Software_System_Award) für Tcl
2024-05-12 10:15:38 +00:00
ausgezeichnet. Tcl kann sowohl als eingebettete Scriptsprache als auch als
allgemeine Programmier-Sprache verwendet werden. Tcl kann auch als portable
C-Bibliothek verwendet werden. Sogar in Fällen in denen die Script-Fähigkeiten
nicht nötig sind. Denn Tcl stellt Daten-Strukturen wie dynamische Zeichenketten,
2024-05-12 10:15:38 +00:00
Listen und Hash-Tabellen bereit. Die C-Bibliothek stellt auch portable
Funktionen zur Verfügung: Laden von dynamischen Bibliotheken, Zeichenketten
2024-09-08 20:13:10 +00:00
Formatierung und Codekonvertierung, Dateisystemoperationen, Netzwerkoperationen
und mehr.
Verschiedenste herausragende Fähigkeiten von Tcl:
* Praktische Cross-Platform Netzwerk-API
* Vollständig virtualisiertes Dateisystem
* Stapelbare I/O Kanäle
* Asynchron bis zum Kern
* Vollständige Ko-Routinen
* Robustes und einfach zu verwendendes Thread-Modell
Wenn Lisp ein Listen-Prozessor ist, dann ist TCl ein Zeichenketten-Prozessor.
Alle Werte sind Zeichenketten. Eine Liste ist ein Zeichenketten-Format. Eine
Prozedur-Definition ist ein Zeichenketten-Format. Um leistungsfähig zu sein,
2024-08-25 16:45:47 +00:00
werden Tcl-intern diese Zeichenketten in Strukturierter-Form gepuffert. Ein
Beispiel: Der "list" Befehl arbeitet mit diesen internen gepufferten
Repräsentationen. Tcl kümmert sich selbständig darum die String-Repräsentationen
zu aktualisieren, falls dies im Skript benötigt werden sollten. Das Kopieren-
2024-09-07 12:47:27 +00:00
beim-Schreiben-Design von Tcl erlaubt es Skript-Autoren mit großen Daten-
2024-05-12 10:15:38 +00:00
Strukturen zu arbeiten ohne zusätzlichen Speicher-Overhead. Prozeduren werden
automatisch byte-kompiliert außer sie verwenden dynamische Befehle wie zum
Beispiel "uplevel", "upvar und "trace".
2024-05-12 10:15:38 +00:00
Es ist eine Freude in Tcl zu programmieren. Hacker-Typen werden gefallen daran
finden, wenn sie Lisp, Forth oder Smalltalk interessant finden. Tcl wird auch
2024-05-12 10:15:38 +00:00
Ingenieuren und Wissenschaftlern gefallen die nur den Job erledigen wollen,
und zwar mit Werkzeugen die sich ihrem Willen anpassen. Bei Tcl ist jegliche
2024-05-12 10:15:38 +00:00
Funktionalität in Befehlen ausgeführt, selbst Dinge wie Schleifen und
Mathematische-Funktionen die bei anderen Sprachen normalerweise Teil der Syntax
2024-05-12 10:15:38 +00:00
sind. Das erlaubt Tcl in den Hintergrund von Domänen spezifischen Sprachen zu
treten die das jeweilige Projekt gerade benötigt. Die Tcl-Syntax ist sehr
leichtgewichtig. Sie ist selbst leichtgewichtiger als die Syntax von Lisp.
Tcl steht dir einfach nicht im Weg.
```tcl
#! /bin/env tclsh
################################################################################
## 1. Richtlinien
################################################################################
# Tcl ist nicht Bash oder C! Das muss gesagt werden, denn standard Shell-Quoting
# funktioniert fast mit Tcl. Daher glauben viele sie können diese Syntax für
# Tcl übernehmen. Am Beginn funktioniert das meist, führt aber schnell zu
# Frustrationen wenn die Skripte komplexer werden.
# Eckige-Klammern sind nur Quoting-Mechanismen, keine Code-Block-Konstruktoren
# und auch keine Listen-Konstruktoren. In Tcl gibt es diese beiden Dinge nicht.
# Eckige-Klammern werden verwendet um Spezial-Zeichen in Prozeduren zu escapen
2024-05-12 10:15:38 +00:00
# und in Zeichenketten die als Listen formatiert sind.
################################################################################
## 2. Syntax
################################################################################
# Jede Zeile ist ein Befehl. Das erste Wort ist der Name des Befehls, jedes
# weitere Wort ist ein Argument des Befehls. Wörter sind begrenzt durch
# Leerzeichen. Da jedes Wort auch ein String ist, sind keine speziellen
2024-05-12 10:15:38 +00:00
# Auszeichnungen wie Anführungs-Zeichen, Klammern oder Backslashes nötig.
# Selbst wenn Anführungs-Zeichen verwendet werden, denn sie sind ja keine
# String-Konstruktoren, sondern nur Escape-Zeichen.
set greeting1 Sal
set greeting2 ut
set greeting3 ations
# Strichpunkte begrenzen auch Befehle
set greeting1 Sal; set greeting2 ut; set greeting3 ations
2024-09-08 20:13:10 +00:00
# Das Dollar-Zeichen zeigt eine Variablen-Substitutionen an.
set greeting $greeting1$greeting2$greeting3
2024-09-08 20:13:10 +00:00
# Eckige-Klammern zeigen Befehls-Substitutionen an. Das Ergebnis des Befehls wird an
# Stelle des Klammern-Ausdrucks eingefügt. Wenn man dem "set" Befehl nur den
# Namen einer Variablen übergibt, gibt er den Wert der Variablen zurück.
set greeting $greeting1$greeting2[set greeting3]
# Befehls-Substitution sollte eigentlich Script-Substitution heißen, denn ein
# komplettes Script, und nicht nur ein Befehl, kann zwischen die Eckigen-Klammern
# geschrieben werden. Der "incr" Befehl erhöht den Wert einer Variable um 1
# und gibt den neuen Wert der Variable zurück.
set greeting $greeting[
incr i
incr i
incr i
]
2024-09-08 20:13:10 +00:00
# Der Backslash unterdrückt die Bedeutung von Sonderzeichen
set amount \$16.42
# Der Backslash macht bestimmte Zeichen zu Sonderzeichen
puts lots\nof\n\n\n\n\n\nnewlines
# Ein Wort das in geschweiften Klammern eingeschlossen wurde ist von jeglichen
# speziellen Interpretationen ausgeschlossen. Eine Ausnahme bilden Backslashes
# vor geschweiften Klammern, hiermit wird die geschweifte Klammer von der Suche
# nach der schließenden geschweiften Klammer ausgeschlossen.
set somevar {
Das ist ein literales $ Zeichen, diese geschweifte Klammer \} wird nicht
als Ende interpretiert.
}
# Bei einem Wort das in doppelten Anführungszeichen steht verlieren Leerzeichen
# ihre spezielle Bedeutung.
set name Neo
set greeting "Hallo, $name"
#Variablen-Namen können irgend eine Zeichenkette sein.
set {first name} New
# Die Geschweifte-Klammern-Form der Variablen-Substitution kann sehr komplexe
# Variblen-Namen handhaben.
set greeting "Hello, ${first name}"
# Der "set" Befehl kann immer anstatt einer Variablen-Substition verwendet
# werden.
set greeting "Hello, [set {first name}]"
# Mit dem Expansions-Operator "{*}" werden Wörter innerhalb eines Wortes wieder
# individuell als Teile des aktuellen Befehls behandelt.
set {*}{name Neo}
# Ist Äquivalent zu
set name Neo
2024-09-07 12:47:27 +00:00
# Ein Array ist eine spezielle Variable die also Container für andere Variablen
# dient.
set person(name) Neo
set person(gender) male
set greeting "Hello, $person(name)"
# Ein Namensraum enthält Befehle und Variablen
namespace eval people {
namespace eval person1 {
variable name Neo
}
}
#Der volle Name einer Variablen beihaltet den/die umschließenden
# Namensraum/Namensräume begrenzt durch zwei Doppelpunkte.
set greeting "Hello $people::person1::name"
```
```tcl
################################################################################
## 3. Einige Notizen
################################################################################
# Jede weitere Funktion ist über Befehle implementiert. Von nun an kommt keine
# neue Syntax hinzu. Alles weitere das es über Tcl zu lernen gibt ist das
# Verhalten individueller Befehle und die bedeutung ihrer Argumente.
# Um einen Interpreter zu bekommen mit dem man nichts mehr machen kann, lösche
# einfach den globalen Namensraum. Das ist nicht sehr sinnvoll, zeigt aber die
# Natur von Tcl.
namespace delete ::
# Wegen des Verhaltens der Namens-Auflösung ist es sicherer den "variable"
# Befehl zu verwenden um in einem Namensraum einen Wert zu deklarieren oder
2024-09-08 20:13:10 +00:00
# zuzuweisen. Wenn eine Variable mit dem Namen "name" bereits im globalen
# Namensraum existiert, bewirkt der "set" Befehl das der globalen Variable ein
# Wert zugewiesen wird, anstatt eine Variable im lokalen Namensraum zu erzeugen
namespace eval people {
namespace eval person1 {
variable name Neo
}
}
# Es kann immer der vollständige Name einer Variable verwendet werden, falls
# gewünscht.
set people::person1::name Neo
################################################################################
## 4. Befehle
################################################################################
# Berechnungen werde mit dem "expr" Befehl durchgeführt.
set a 3
set b 4
set c [expr {$a + $b}]
# Since "expr" performs variable substitution on its own, brace the expression
# to prevent Tcl from performing variable substitution first. See
# Da der "expr" Befehl eigene Variablen-Substitutionen durchführt, setze den
# zu berechnenden Ausdruck in Eckige-Klammern. Das hindert Tcl daran Variablen-
# Substitutionen durchzuführen. Für Details siehe:
# "http://wiki.tcl.tk/Brace%20your%20#%20expr-essions"
# Der "expr" Befehl versteht Variablen- und Befehls-Substitutionen
set c [expr {$a + [set b]}]
# Der "expr" Befehl stellt Mathematische-Funktionen zur Verfügung.
set c [expr {pow($a,$b)}]
# Mathematische Operatoren sind als Befehle auch im Namensraum
# ::tcl::mathop verfügbar.
::tcl::mathop::+ 5 3
# Befehle können aus anderen Namensräumen importiert werden.
namespace import ::tcl::mathop::+
set result [+ 5 3]
# Neu Befehle werden mit dem "proc" Befehl gebildet.
proc greet name {
return "Hello, $name!"
}
#Es können mehrere Parameter spezifiziert werden.
proc greet {greeting name} {
return "$greeting, $name!"
}
# Wie bereits erwähnt, geschwungene Klammern erzeugen keinen Code-Block.
# Jeder Wert, sogar das dritte Argument für den "proc" Befehl ist eine
# Zeichenkette. Der vorherige Befehl kann daher auch ohne
# geschwungene Klammern geschrieben werden:
proc greet greeting\ name return\ \"Hello,\ \$name!
# Wenn der letzte Parameter der literale Wert "args" ist, sammelt dieser Wert
# alle übrigen Argumente des Befehls ein wenn dieser aufgerufen wird.
proc fold {cmd args} {
set res 0
foreach arg $args {
set res [$cmd $res $arg]
}
}
fold ::tcl::mathop::* 5 3 3 ;# -> 45
# Bedingte Ausführung ist auch als Befehl implementiert
if {3 > 4} {
puts {This will never happen}
} elseif {4 > 4} {
puts {This will also never happen}
} else {
puts {This will always happen}
}
# Auch Schleifen sind Befehle. Das erste, zweite und dritte Argument des "for"
# Befehls wird als mathematischer Ausdruck behandelt.
for {set i 0} {$i < 10} {incr i} {
set res [expr {$res + $i}]
}
# Das erste Argument des "while" Befehls wird auch als mathematischer Ausdruck
# behandelt.
set i 0
while {$i < 10} {
incr i 2
}
# Eine Liste ist eine speziell formatierte Zeichenkette. Im einfachsten Fall
# genügen Leerzeichen als Trennzeichen zwischen den einzelnen Werten.
set amounts 10\ 33\ 18
set amount [lindex $amounts 1]
# Geschwungene Klammern und Backslashes können verwendet werden um komplexe
# Werte in einer Liste zu formatieren. Eine Liste sieht aus wie ein Skript,
2024-09-08 20:13:10 +00:00
# allerdings verlieren Zeilenumbrüche und Doppelpunkte ihre
# besondere Bedeutung. Diese Funktionalität macht Tcl homoikonisch. Die
2024-08-25 16:45:47 +00:00
# folgende Liste enthält drei Elemente.
set values {
one\ two
{three four}
five\{six
}
# Da Listen auch Zeichenketten sind, kann man Zeichenketten-Operationen auf
# ihnen anwenden. Allerdings mit dem Risiko die Formatierung der Liste zu
# beschädigen.
set values {one two three four}
set values [string map {two \{} $values] ;# $values is no-longer a \
properly-formatted listwell-formed list
# Der sicherste Weg korrekt formatierte Liste zu erzeugen, ist den "list"
# Befehl zu verwenden.
set values [list one \{ three four]
lappend values { } ;# Ein Leerzeichen als Element der Liste hinzufügen
2024-09-07 12:47:27 +00:00
# Mit "eval" können Werte als Skripts evaluiert werden.
eval {
set name Neo
set greeting "Hello, $name"
}
# Eine Liste kann immer an "eval" übergeben werden, solange die Liste einen
2024-09-07 12:47:27 +00:00
# einzigen Befehl enthält.
eval {set name Neo}
eval [list set greeting "Hello, $name"]
# Daher: Wenn "eval" verwendet wird, verwende [list] um den gewünschten Befehl
# aufzubauen.
set command {set name}
lappend command {Archibald Sorbisol}
eval $command
2024-09-08 20:13:10 +00:00
# Es ist ein häufiger Fehler die Listenfunktionen beim Aufbauen von Listen
# nicht zu verwenden.
set command {set name}
append command { Archibald Sorbisol}
eval $command ;# Hier passiert eine Fehler, denn der "set" Befehl hat nun zu \
viele Argumente {set name Archibald Sorbisol}
# Dieser Fehler kann auch leicht beim "subst" Befehl passieren.
set replacement {Archibald Sorbisol}
set command {set name $replacement}
set command [subst $command]
eval $command ;# The same error as before: too many arguments to "set" in \
{set name Archibald Sorbisol}
# Die korrekte Vorgangsweise ist es den substituierten Wert mit dem "list"
# Befehl zu formatieren.
set replacement [list {Archibald Sorbisol}]
set command {set name $replacement}
set command [subst $command]
eval $command
# Der "list" Befehl wird sehr häufig verwendet um Werte zu formatieren die
# in Tcl Skript Vorlagen substituiert werden. Es gibt dazu viele Beispiele,
# siehe unterhalb.
# Der "apply" Befehl evaluiert eine Zeichenkette als Befehl.
set cmd {{greeting name} {
return "$greeting, $name!"
}}
apply $cmd Whaddup Neo
# Der "uplevel" Befehl evaluiert ein Skript in einem höher liegenden
Gültigkeitsbereich.
proc greet {} {
uplevel {puts "$greeting, $name"}
}
proc set_double {varname value} {
if {[string is double $value]} {
uplevel [list variable $varname $value]
} else {
error [list {not a double} $value]
}
}
# Der "upvar" Befehl verknüpft eine Variable im aktuellen Gültigkeitsbereich
# mit einer Variable in einem höher liegenden Gültigkeitsbereich.
proc set_double {varname value} {
if {[string is double $value]} {
upvar 1 $varname var
set var $value
} else {
error [list {not a double} $value]
}
}
# Werde den eingebauten "while" Befehl los.
rename ::while {}
2024-09-08 20:13:10 +00:00
# Definieren einen neuen "while" Befehl mithilfe des "proc" Befehls.
# Ausführlichere Fehler-Behandlung wird dem Leser als Übung überlassen.
proc while {condition script} {
if {[uplevel 1 [list expr $condition]]} {
uplevel 1 $script
tailcall [namespace which while] $condition $script
}
}
# Der "coroutine" Befehl erzeugt einen separaten Call-Stack, zusammen mit einem
# Befehl um diesem Call-Stack zu verwenden. Der "yield" Befehl unterbricht
# die Ausführung des aktuellen Call-Stacks.
proc countdown {} {
#send something back to the initial "coroutine" command
yield
set count 3
while {$count > 1} {
yield [incr count -1]
}
return 0
}
coroutine countdown1 countdown
coroutine countdown2 countdown
puts [countdown 1] ;# -> 2
puts [countdown 2] ;# -> 2
puts [countdown 1] ;# -> 1
puts [countdown 1] ;# -> 0
2024-09-08 20:13:10 +00:00
puts [countdown 1] ;# -> invalid command name "countdown1"
puts [countdown 2] ;# -> 1
```
## Referenzen
[Official Tcl Documentation](http://www.tcl.tk/man/tcl/)
[Tcl Wiki](http://wiki.tcl.tk)
[Tcl Subreddit](http://www.reddit.com/r/Tcl)