TCL Basics
TCL Basics
############
TCL stands for Tool Command Language.
Tcl is a string based scripting language. The source code is
compiled into bytecode, which is later interpreted by the Tcl
interpreter. It was created by John Osterhout in 1988. The
purpose was to create a language which is easily embeddable
into applications.
To start TCL shell in Linux terminal: tclsh
To run TCL sripts: tclsh <file_name.tcl>
############
Tcl uses the pound character, #, for comments.
puts stdout {Hello, World!}
=>Hello, World!
Curly braces are used to group words together into a single
argument.
############
############
A common use of backslashes is to continue long commands on
multiple lines. This is necessary because a newline terminates a
command.
Continuing long lines with backslashes:
set totalLenght [expr [string lenght $one] + \
[string length $two]]
############
Double quotes and curly braces are used to group words together
into one argument. The difference between double quotes and
curly braces is that quotes allows substitution to occur in the
############
The square bracket syntax used for command substitution does
not provide grouping.
The following is the redundant use of double quotes:
puts stdout "[expr $s + $p]"
############
Tcl uses the proc command to define procedures. Once defined,
a Tcl procedure is used just like any of the other built-in Tcl
commands. The basic syntax to define a procedure is:
proc name arglist body
The first argument is the name of the procedure being defined.
The second argument is a list of parameters to the procedure.
############
A while loop to compute factorial
proc Factorial {x}{
set i 1; set product 1
while {$i<=$x}{
set product [expr {$product*$i}]
incr i
}
return $product
}
Factorial 10
=>3628800
############
############
A recursive definition of factorial
proc Factorial {x}{
if{$x <=1}{
return 1
}else{
return [expr {$x*[Factorial [expr {$x - 1}]]}]
}
}
############
You can delete a variable with unset command:
unset varName1
Any number of variable names can be passed to the unset
command. However, unset will raise an error if a variable is not
already defined, unless the -nocomplain is given. Use -- to unset
a variable named -nocomplain.
############
The existence of a variable can be tested with the info exists
command.
############
Command arguments are separated by white space, unless
arguments are grouped with curly braces or double quotes.
Grouping with curly braces, {}, prevents substitutions.
Grouping with double quotes, " ", allows substitutions.
Grouping decisions are made before substitutions are performed,
which means that the values of variables or command results do
not affect grouping.
Square brackets, [], cause command substitution. Everything
between the brackets is treated as a command, and everything
including the brackets is replaced with the result of the
command. Nesting is allowed in square brackets.
############
linsert = inset elements into a list.
lindex = Fetch an element of a list.
lappend = Add element to the end of a list.
join = Concatenate list elements with a given separator string.
global = Declare global variables.
glob = Expand a pattern to matching file names.
gets = Read a line of input from an I/O stream.
format = Format a string similar to C sprintf.
trace =
############
set str1 "ksadfal"
set str2 "jaskdfja"
string equal -nocase $str1 $str2
It will return 1 if str1 and str2 are equal. Here -nocase is used for
case insensitive comparison.
############
string first $str1 $str2
It will return the index of the first occurrence of str1 in str2. The
index count from zero. If str1 is not found in str2 then it will
return -1.
It will return the character in str1 at index 3. Use end for the last
character.
string index $str1 end
string index $str1 end-1
############
string length $str1
It will return the number of characters in string str1.
############
The map command takes two arguments: a list and a Tcl
command. For each element in the list, it executes the given
command with the list element appended as an additional
arguments. With the results of all the commands it generates a
new list, and then returns this list as its results.
string map {abc def} abcabcabc
=>defdefdef
Tcl has mapped each occurrence of the string "abc" and replaced
it with the string "def".
############
string match command returns 1 if str matches the pattern, else
0.It implements glob-style pattern matching.
############
string range str i j
Returns the range of characters in str from i to j.
string range "abcdefg" 3 5
=>def
############
string repeat "ab" 3
=>ababab
############
string replace "this is a bad example" 10 12 good
=>this is a good example
=>1
############
You can perform a simple string replacement with the string
replace command. It accepts a string as an argument along with
the beginning and ending indices of a sequence of characters to
delete, as well as an optional string argument to insert in their
place:
string replace "San Diego, California" 4 8 "Francisco"
=>San Francisco, California
string replace "parsley, sage, rosemary, and thyme" 0 8
=>sage, rosemary, and thyme
############
Tcl's format command provides facilities like those of the sprintf
procedure from the ANSI C library.
format "The square root of 10 is %.3f" [expr sqrt(10)]
=>The square root of 10 is 3.162
############
The append command takes a variable name as its first argument
and concatenates its remaining arguments onto the current value
of the named variable. The variable is created if it does not
already exist:
set foo z
append foo a b c
set foo
=>zabc
append x "some new stuff"
is always faster than this:
set x "$x some new stuff"
############
A Tcl list is a sequence of values.
A list in Tcl consists of a string whose items are separated by
white space.
A list has its elements separated by white space. Braces or
quotes can be used to group words with white space into a single
list element.
To assign a list to a variable we can do this,
set list1 {A B C D E}
or this,
set list1 [list A B C D E]
The second method is better because the use of the list command
makes it much clearer that a list is being created. To print a raw
list to the console we use the puts command,
It is possible for one list to have another list embedded within it,
for example,
set list1 [list A B [list 1 2 3] C D E]
A list may also contain consecutive lists, for example,
set list1 [list DOG CAT MULE]
set list2 [list dog cat mule]
set list3 [list $list1 $list2]
############
To step through a list the foreach command is used,
foreach item $list1 {
puts $item
}
Although the use of foreach, shown above, works well when
printing a simple list it fails to print items contained within
embedded lists. A partial solution to this problem is to
encapsulate the list handling code within a procedure.
proc printlist { inlist } {
############
set nums { 1 2 3 4 5 6 7 }
puts [llength $nums]
The llength command returns a length of the list.
lappend nums 7 8 9
puts $nums
456789
The lappend appends data to the list.
puts $nums
456789
############
set animals1 { lion eagle elephant dog cat }
set animals2 { giraffe tiger horse dolphin }
puts $animals
lion eagle elephant dog cat giraffe tiger horse dolphin
The lreplace command replaces dog and cat with buffalo and
crocodile.
############
set names { John Mary Lenka Veronika Julia Robert }
set nums { 1 5 4 3 6 7 9 2 11 0 8 2 3 }
To sort list elements, we can use the sort command. The
command does not modify the original list. It returns a new
sorted list of elements.
We have two lists. In the first we have strings, in the second
numbers.
The default sorting is the ascii sorting. The elements are sorted
by their positions in the ascii table.
puts [lsort $names]
John Julia Lenka Mary Robert Veronika
In the above line, we get the second element of the first nested
list.
% set a {a b c d}
abcd
% lset a 2 X
abXd
% puts $a
abXd
lset a 1 2 newValue
or
lset a {1 2} newValue
replaces element 2 of sublist 1 with newValue.
############
split makes a list from a string by splitting the string up into list
elements.
If invoked with one argument (the string), the string is split on
whitespace
If invoked with two arguments, the second argument is used as a
set of characters to split on
If the second argument is the empty string, the string is split
between every character, resulting in a list of characters. (This is
like the old Lisp explode function.)
split
"keith:cdridjyhTp2FQ:100:1100:Keith
Waclena:/home/keith:/host/bin/zsh" :
=> keith cdridjyhTp2FQ
/home/keith /host/bin/zsh
split abcde {}
=> a b c d e
100
1100
{Keith
Waclena}
lvarcat x 1 2 {a b} 3
=> x y 1 2 {a b} 3
set x [list x y]
=> x y
set x [concat $x 1 2 {a b} 3]
=> x y 1 2 {a b} 3
############
lvarpush and lvarpop make it easy to use lists as stacks. lvarpush
adds a new element to the beginning of the list stored in the
named variable (the variable is created if necessary):
set x
Error: can't read "x": no such variable
lvarpush x 1
=>
lvarpush x 2
=>
lvarpush x 3
=>
set x
=> 3 2 1
lvarpop x
=> 3
set x
=> 2 1
lvarpop x
=> 2
set x
=> 1
lvarpop x
=> 1
set x
=>
Stacks can be implemented with set, concat and lindex, but
lvarpush and lvarpop are more readable and more efficient:
set x {}
=>
set x [concat 1 $x]
=> 1
set x [concat 2 $x]
=> 2 1
set x [concat 3 $x]
=> 3 2 1
lindex $x 0
=> 3
set x [lreplace $x 0 0]
lindex $x 0
=> 2
set x [lreplace $x 0 0]
lindex $x 0
=> 1
set x [lreplace $x 0 0]
set x
=>
Both lvarpush and lvarpop will manipulate other elements of the
list than just the first, but I recommend avoiding these forms and
using linsert and lreplace instead.
############
lmatch is similar to lsearch, but it returns not the first matching
element, but rather a list of all matching elements. Any of the
standard Tcl pattern matching options may be used to determine
how the matching is done.
############
intersect treats two list arguments as sets and returns the set (list)
which is their intersection:
intersect {a b c} {x y z}
=>
intersect {a b c} {x a c}
=> a c
intersect {a b c} {x a a a c a}
=> a c
############
intersect3 is similar to intersect, but returns a list of three results.
Call the first argument to intersect3 A and the second B. Then
incr range 1
} elseif {$key == 0} {
return $range
} else {
incr range -1
}
Any number of conditionals can be chained in this manner.
However, the switch command provides a more powerful way to
test multiple
conditions.
############
Using switch for an exact match:
switch -exact -- $value {
foo { doFoo; incr count(foo) }
bar { doBar; return $count(foo)}
default { incr count(other) }
}
############
A comment can occur only where the Tcl parser expects a
command to begin. This restricts the location of comments in a
switch command. You must put them inside the command body
associated with a pattern, as
shown here:
switch -- $value {
# this comment confuses switch
pattern { # this comment is ok }
}
############
While statement:
set i 0 ; while {$i<10} {incr i}
############
A while loop to read standard input:
set numLines 0 ; set numChars 0
while {[gets stdin line] >= 0} {
incr numLines
incr numChars [string length $line]
}
############
}
set aList
=> 0 3 6 9
############
You can control loop execution with the break and continue
commands. The break command causes immediate exit from a
loop, while the
continue command causes the loop to continue with the next
iteration. There is no goto command in Tcl.
############
Until now we have ignored the possibility of errors. In practice,
however, a command will raise an error if it is called with the
wrong number of arguments, or if it detects some error condition
particular to its implementation. An uncaught error aborts
execution of a script.
The catch command is used to trap such errors. It takes two
arguments:
catch command ?resultVar?
exit 1
}
############
The error command raises an error condition that terminates a
script unless it is trapped with thec atch command. The
command takes up to
three arguments:
error message ?info? ?code?
The message becomes the error message stored in the result
variable of the catch command.
If the info argument is provided, then the Tcl interpreter uses
this to initialize the errorInfo global variable. That variable is
used to collect a stack trace from the point of the error. If the
info argument is not provided, then the error command itself is
used to initialize the errorInfo trace.
set foo
Error: can't read "foo": no such variable
############
The return command is used to return from a procedure. It is
needed if return is to occur before the end of the procedure
body, or if a
constant value needs to be returned. As a matter of style, I also
use return at the end of a procedure, even though a procedure
returns the
value of the last command executed in the body.
############