A Tcl script consists of one or more commands, separated by newlines or semicolons.
command arg1 arg2 arg3 ...
Commands are the basic execution elements. A command is followed by zero or more words which are parameters or arguments, each separated by white space or tabs.
ex: puts stdout "My first Tcl script." = > My first Tcl script.
Two step process: parsing and execution.
Note: arguments are quoted by default -- if you want evaluation, you
must ask for it explicitly
For example:
set a 5
set b a+8
The first command assigns the string 5 to variable a. The second command takes the string a+8 and stores it as the new value for b. For y to take on the value 13, you must explicitly evaluate it, as in:
set a 5
set b [expr $a+8]
Each pair of brackets invokes an additional evaluation. The one thing you must remember about Tcl is that it does just what you think it will. The evaluation model is very straightforward. There is a single command and zero or more arguments. Those arguments may in turn be commands with arguments that must be evaluated. The commands' return values become the argument to the original command to be evaluated.
State is maintained in Tcl through the use of variables, and are both declared and instantiated with the "set" command.
example:
set loopCounter 0
Note that a separate variable declaration is not necessary. Variable values are retrieved using the dollar sign, which will be familiar to shell programmers and Perl developers, but there are slightly different rules associated with when and when not to use the dollar sign.
example:
if ($loopCounter > 10) { do something }
Simple variables have a name and a value (stored as a string).
Arrays are a collection of elements, each of which is a variable with it own name and value. Array names and element names may be arbitrary strings (i.e. sometimes called associative arrays to distinguish them from arrays that require elements to be integers).
Example:
set yearTotal 0 foreach month {Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec} { set yearTotal [expr $yearTotal+$earnings($month)] }
Tcl only implements one-dimensional arrays, but multidimensional arrays are simulated by concatenating multiple indices into a single element name.
set matrix(1,1) 140 set matrix(1,2) 218 set matrix(1,3) 84 set i 1 set j 2 set cell $matrix($i,$j) => 218
*Note that there are no spaces because the three element names are 1,1 and 1,2 and 1,3. Thus:
matrix(2,5)is not the same as
matrix(2, 5)
Expressions combine operands and operators to create new values.
Syntax: expr arg ?arg arg ...?
<< and >> use the right operand as the shift count (in bits). During left shifts, zeros are shifted into the low order bytes. Right shifts are "arithmetic right shifts" which shifts zeros for positive number, and ones for negative numbers (unlike ANSI C which is machine dependent). The ~ is a one's complement operator that flips each bit.
Syntax: expr { ($a < $b) ? $a : $b}
Substitutions can occur in two ways for expression operands.
Example:
expr { 2*sin($x) }
The braces causes Tcl parser to not do a variable substitution for x. When the expression evaluator encounters the dollar sign, it performs variable substitution itself. This is not very useful for the exprcommand, but is useful for other commands like while that evaluate an expression repeatedly and expect to get a different result each time.
Example:
set pow 1 while {$pow<$num} { set pow [expr $pow*2] }
If the braces were omitted in {$pow<$num}, the while's argument would be a constant expression such as 1<44 which would cause in infinite loop.
Tcl allows string operands for some operators: <, >, <=, >=, ==, and !=. For all other operators, the operands must be numeric. Tcl only uses string comparisons if one or both of the operands cannot be parsed as a number.
Example:
set x 0 set y 00 if {$x==$y} { ... }
Arithmetic comparison will be used and the test will evaluate to 1. To force string comparison for numeric operands, use a command such as string compare.
Tcl evaluates expressions numerically whenever possible. String operations are performed only for the relational operators and only if one or both of the operands doesn't make sense as a number. Automatic conversion is done for operands of different types:
Also, use double, and int and round to cast int to real and real to int respectively.
A list is an ordered collection of elements (separated by spaces) where each element can have any string value. Lists can be nested.
Command | Result |
concat ?list list ...? | Joins multiple lists into a single list (each element of each list becomes an element of the result list) and returns the new list. |
join list ?joinString? | Concatenates list elements together with joinString as separator and returns the result. joinString defaults to a space. |
lappend varName value ?value ...? | Appends each value to variable varName as a list element and returns the new value of the variable. Creates the variable if it doesn't exist. |
lindex list index | Returns the index'th element from list (0 refers to the first element). |
linsert list index value ?value ...? | Returns a new list formed by inserting all of the value arguments
as list elements before index'th element of list (0 refers
to the first element).
Example: |
list ?value value ...? | Returns a list whose elements are the value arguments. |
llength list | Returns the number of elements in list. |
lrange list first last | Returns a list consisting of elements first through last of list. If last is end, it selects all elements up to the end of list. |
lreplace list first last ?value value ...? | Returns a new list formed by replacing elements first through last of list with zero or more new elements, each formed from one value argument. |
lsearch ?-exact? ?-glob? ?-regexp? list pattern | Returns the index of the first element in list that matches pattern or -1 if none. The optional switch selects a pattern-matching technique (default: -glob). |
lsort ?-ascii? ?-integer? ?-real? ?-command command? ?-increasing? ?-decreasing? list | Returns a new list formed by sorting the elements of list. The switches determine the comparison function and sorted order (default: -ascii -increasing). |
split string ?splitChars? | Returns a list formed by splitting string at instances of splitChars and turning the characters between these instatnces into list elements. |
if test1 body1 ?elseif test2 body2 elseif ...? ?else bodyn? | |
while test body | |
for init test reinit body | |
foreach varName list body | |
switch ?options? string pattern body ?pattern body ...? switch ?options? string { pattern body ?pattern body ...? } |
Options: -exact (exact matching), -glob (same as string matching), or
-regexp (regular expression matching).
If a script is '-', switch use the script for next pattern (i.e. several patterns can all execute the same script). default pattern used to catch unmatched patterns. |
eval arg ?arg arg ...? | General purpose building block for creating and executing Tcl scripts. It accepts any number of arguments, concatenates all of the args with separator spaces, then evaluates the result as a Tcl script and returns its results which is useful when you need to force another level of parsing. |
Procedures are normal Tcl commands that are useful in packaging modules that can be reused. Procedures can be defined at any time and you can pass arguments by value or by reference. The value returned is the result of the last statement in the body of the procedure, unless explicitly returned with the return command.
Syntax:
proc procedure_name arguments ?args? body
e.g.:
proc plus {a b} {expr $a+$b}
Arguments used inside a procedure are local. To reference global variables, the global command will bind variables within the procedure for the life of the procedure. Arguments can have default values and are specified as follows:
proc inc {value {increment 1}} { expr $value+$increment } incr 42 3 => 45 incr 42 => 43
Defaulted arguments, if any, must be the last arguments for the procedure. If a default is not specified, the argument is required.
Variable number of arguments is supported by args which is put at the end of the argument list. The procedure uses the args argument as a list whose elements are the extra arguments. If there are no extra arguments, args will be set to an empty string.
proc sum args { set s 0 foreach i $args { incr s $i } return $s } sum 1 2 3 4 5 => 15 sum => 0
The upvar command provides a general mechanism for accessing variables outside the context of a procedure. It can be used to access global or local variables in some other active procedure, but is most often used to pass in arrays (because there is no value for an array, just its elements).
Example:
proc parray name { upvar $name a foreach el [lsort [array names a]] { puts "$el = $a($el)" } } set info(age) 37 set info(position) "Vice President" parray info => age = 37 position = Vice President
upvar can also be used to access variables on different levels of the call stack.
upvar #0 other x
makes global variable other accessible via local variable x (#0 specifies access to the global variable other regardless of the level of the call stack).
upvar 2 other x
makes variable other in the caller of the caller of the current procedure accessible as local variable x (2 specifies two levels up in the call stack).
uplevel is a command that is a cross between eval and upvar. It evaluates its argument(s) as a script, just like eval, but the script is evaluated in the variable context of a different stack level like upvar. With uplevel, you can define new control structures as Tcl procedures.
Example:
proc do {varName first last body}{ upvar $varName v for {set v $first} {$v <= $last} {incr v} uplevel $body } } set squares {} do i 1 5 { lappend squares [expr $i*$i] } set squares => 1 4 9 16 25
Like upvar, uplevel takes an optional inital argument that specifies an explicit stack level.
Tcl is 8 bit clean (not just ASCII 7 bit subset). Tcl does not apply any interpretation to characters outside of the ASCII subset. Tcl stores strings using a null (zero) character for termination, so it is not possible to store zero characters in a string. To represent binary data, convert it to a form that includes no zero characters, for example, by translating bytes to their corresponding hexadecimal values.
Simplest form of Tcl pattern matching.
Syntax:
string match pattern string
Return 1 if match, 0 if no match. Special characters used in matching
* | Matches any sequence of zero or more characters. |
? | Matches any single character. |
[chars] | Matches any single character in chars. If chars contains a sequence of the form a-b, any character between a and b inclusive will match. |
\x | Matches the single character x. This provides a way to avoid special interpretation for any of the characters *?[]\ in the pattern. |
Regular expression patterns can have several layers of structure. Basic building blocks are called atoms and the simplest form regular expression consists of one or more atoms. For a regular expression to match an input string, there must be a substring of the input where each of the regular expression's atoms (or other components) matches the corresponding part of the substring. E.g. regular expression abc matches any string containing abc such as abcdef or xabcy.
For example, the following pattern matches any string that is either a hexadecimal number or a decimal number.
^((0x)?[0-9a-fA-F]+|[0-9]+)$
Syntax:
regexp ?-nocase? ?-indices? {pattern} input_string ?variable ...?
and returns 0 if there is no match, 1 if there is a match.
Note, the pattern must be enclosed in braces so that the characters $, [, and ] are passed through to the regexp command instead of triggering variable or command substitution.
If regexp is invoked with arguments after the input string, each argument is treated as a name of a variable. The first variable is filled in with the substring that matched the entire regular expression. The second variable is filled in with the portion of the substring that matched the leftmost leftmost parenthesized subexpression within the pattern; the third third variable is filled in with the the match for the next parenthesized subexpression and so on. If there are more variables names than parenthesized subexpressions, the extra variables are set to empty strings.
Example:
regexp {([0-9]+) *([a-z]+)} "Walk 10 km" a b c
variable a will have the value "10 km", b will have "10" and c will have "km".
The switch -nocase specifies to match without case sensitivity. The switch -indices specifies that the additional variables should not be filled in with the values of the matching substrings, but with a list giving the first and last indices of the substring's range within the input string.
Example:
regexp -indices {([0-9]+) *([a-z]+)} "Walk 10 km"a b c
variable a will have the value "5 9", b will have "5 6" and c will have "8 9".
Characters | Meaning |
. | Matches any single character |
^ | Matches the null string at the start of the input string. |
$ | Matches the null string at the end of the input string. |
\x | Matches the character x. |
[chars] | Matches any single character from chars. If the first character of chars is ^, the pattern matches any single character not in the remainder of chars. A sequence in the form of a-b in chars is treated as shorthand for all of the ASCII characters between a and b inclusive. If the first character in chars (possibly following a ^) is ], it is treated literally (as part of chars instead of a terminator). If a - appears first or last in chars, it is treated literally. |
(regexp) | Matches anything that matches the regular expression regexp. Used for grouping and for identifying pieces of the matching substring. |
* | Matches a sequence of 0 or more matches of the preceding atom. |
+ | Matches a sequence of 1 or more matches of the preceding atom. |
? | Matches either a null string or a match of the preceding atom. |
regexp1 | regexp2 | Matches anything that matches either regexp1 or regexp2. |
Syntax:
regsub ?-nocase? ?-all? pattern input_string replacement_value new_string
The first argument to regsub is the regular expression pattern. If a match is found in the input string, regsub return 1, otherwise it returns 0 (like regexp command). If the pattern is matched, the substring of the input string is replaced by the third argument and the new string is stored in the fourth argument. If a match was not found, the fourth argument contains the original input string. Two switches can be used: -nocase is equivalent to the nocase switch in the regexp command; -all causes every matching substring in the input string to be replaced.
The format command provides facilities like sprintf in ANSI C.
Example:
format "The square root of 10 is %.3f" [expr exp(10)]
=> The square root of 10 is 3.162
Other format specifiers:
%s | String |
%d | Decimal integer |
%f | Real number |
%e | Real number in mantissa-exponent form |
%x | Hexadecimal |
%c | Character |
The format command can also be used to change the representation of a value. For example, formatting an integer with %c generates the ASCII character represented by the integer.
Syntax:
scan parse_string format_string ?variable ...?
Example:
scan "16 units, 24.2 margin" "%d units, %f" a b
=> 2
String manipulation commands are options of the string command.
string index "See Spot run." 5
=> p
string range "See Spot run." 5 8
=> Spot
string range "See Spot run." 5 end
=> Spot run.
Searching for a substring with first or last returns the position of the first character of the substring (starting at 0 for the first character in the input string). Returns -1 if no match was found.
string first th "The trains were thirty minutes late this past week"
=> 16
string last th "The trains were thirty minutes late this past week"
=> 36
Compare returns 0 if the strings match, -1 if the first string sorts before the second, and 1 if the first string sorts after the second.
string compare twelve thirteen
=> 1
string compare twelve twelve
=> 0
string length "not too long"
=> 12
string toupper "Hello, World!"
=> HELLO, WORLD!
string tolower "You are lucky winner 13!"
=> you are lucky winner 13!
string trim abracadabra abr
=> cad
string trim takes a string to trim and an optional set of trim characters and removes all instances of the trim characters from both the beginning and end of its argument string, returning the trimmed string as result. trimleft and trimright options work in the same way except they only remove the trim characters from the beginning or end of the string. The trim comands are mostly commonly used to remove excess white space; if no trim characters are specified, they default to the white space characters (space, tab, newline, carriage return, and form feed).
Many of the examples above are from John Ousterhout's book:
Tcl and the Tk Toolkit
Author: John K. Ousterhout
Publisher: Addison Wesley, 1994
While there are many more books on the Tcl language, this book, in my opinion, is one of the best.