10.38.2.3 Commands

Now that the Tcl syntax and variables have been been dealt with, we will now look at some of the commands that are available.

Each command when executed returns a value. The return value will be described along with the command.

A quick word about the notation used to describe Tcl commands. In general, a description of a command is the name of the command followed by its arguments separated by spaces. An example is:

     set varName ?value?

which is a description of the Tcl set command, which takes a variable name varName and an optional argument, a value.

Optional arguments are enclosed in question mark, ?, pairs, as in the example.

A series of three dots ... represents repeated arguments. An example is a description of the unset command:

     unset varName ?varName varName ...?

which shows that the unset command has at least one compulsory argument varName but has any number of subsequent optional arguments.

The most used command over variables is the set command. It has the form

     set varName ?value?

The value of value is determined, the variable varName is set to it, and the value is returned. If there is no value argument, the value of the variable is simply returned. It is thus used to set and/or get the value of a variable.

The unset command is used to remove variables completely from the system:

     unset varName ?varName varName ...?

which given a series of variable names deletes them. The empty string is always returned.

There is a special command for incrementing the value of a variable:

     incr varName ?increment?

which, given the name of a variable thats value is an integer string, increments it by the amount increment. If the increment part is left out, it defaults to 1. The return value is the new value of the variable.

Expressions are constructed from operands and operators and can then be evaluated. The most general expression evaluator in Tcl is the expr command:

     expr arg ?arg arg ... arg?

which evaluates its arguments as an expression and returns the value of the evaluation.

A simple example expression is

     expr 2 * 2

which when executed returns the value 4.

There are different classes of operators: arithmetic, relational, logical, bitwise, and choice. Here are some example expressions involving various operators:

arithmetic $x * 2
relational $x > 2
logical ($x == $y) || ($x == $z)
bitwise 8 & 2
choice ($a == 1) ? $x : $y

Basically the operators follow the syntax and meaning of their ANSI C counterparts.

Expressions to the expr command can be contained in curly brackets in which case the usual substitutions are not done before the expr command is evaluated, but the command does its own round of substitutions. So evaluating a script such as:

     set a 1
     expr { ($a==1) : "yes" ? "no" }

will evaluate to yes.

Tcl also has a whole host of math functions that can be used in expressions. Their evaluation is again the same as that for their ANSI C counterparts. For example:

     expr { 2*log($x) }

will return 2 times the natural log of the value of variable x.

Tcl has a notion of lists, but as with everything it is implemented through strings. A list is a string that contains words.

A simple list is just a space separated series of strings:

     set a {one two three four five}

will set the variable a to the list containing the five strings shown. The empty list is denoted by an open and close curly bracket pair with nothing in between: {}.

For the Prolog programmer, there is much confusion between a Prolog implementation of lists and the Tcl implementation of lists. In Prolog we have a definite notion of the printed representation of a list: a list is a sequence of terms enclosed in square brackets (we ignore dot notation for now); a nested list is just another term.

In Tcl, however, a list is really just a string that conforms to a certain syntax: a string of space separated words. But in Tcl there is more than one way of generating such a string. For example,

     set fred {a b c d}

sets fred to

     "a b c d"

as does

     set fred "a b c d"

because {a b c d} evaluates to the string a b c d, which has the correct syntax for a list. But what about nested lists? Those are represented in the final list-string as being contained in curly brackets. For example:

     set fred {a b c {1 2 3} e f}

results in fred having the value

     "a b c {1 2 3} e f"

The outer curly brackets from the set command have disappeared, which causes confusion. The curly brackets within a list denote a nested list, but there are no curly brackets at the top-level of the list. (We can't help thinking that life would have been easier if the creators of Tcl would have chosen a consistent representation for lists, as Prolog and LISP do.)

So remember: a list is really a string with a certain syntax, space separated items or words; a nested list is surrounded by curly brackets.

There are a dozen commands that operate on lists.

     concat ?list list ...?

This makes a list out of a series of lists by concatenating its argument lists together. The return result is the list resulting from the concatenation.

     lindex list index

returns the index-th element of the list. The first element of a list has an index of 0.

     linsert list index value ?value ...?

returns a new list in which the value arguments have been inserted in turn before the index-th element of list.

     list ?value value ...?

returns a list where each element is one of the value arguments.

     llength list

returns the number of elements in list list.

     lrange list first last

returns a slice of a list consisting of the elements of the list list from index first until index last.

     lreplace list first last ?value ... value?

returns a copy of list list but with the elements between indices first and last replaced with a list formed from the value arguments.

     lsearch ?-exact? ?-glob? ?-regexp? list pattern

returns the index of the first element in the list that matches the given pattern. The type of matching done depends on which of the switch is present -exact, -glob, -regexp, is present. Default is -glob.

     lsort ?-ascii? ?-integer? ?-real? ?-command command? ?-increasing? ?-decreasing{? list

returns a list, which is the original list list sorted by the chosen technique. If none of the switches supplies the intended sorting technique, the user can provide one through the -command command switch.

There are also two useful commands for converting between lists and strings:

     join list ?joinString?

which concatenates the elements of the list together, with the separator joinString between them, and returns the resulting string. This can be used to construct filenames; for example:

     set a {{} usr local bin}
     set filename [join $a /]

results in the variable filename having the value /usr/local/bin.

The reverse of the join command is the split command:

     split string ?splitChars?

which takes the string string and splits it into string on splitChars boundaries and returns a list with the strings as elements. An example is splitting a filename into its constituent parts:

     set a [split /usr/local/src /]

gives a the value {{} usr local src}, a list.

Tcl has the four usual classes of control flow found in most other programming languages:

     if...elseif...else, while, for, foreach, switch, and eval.

We go through each in turn.

The general form of an if command is the following:

     if test1 body1 ?elseif test2 body2 elseif ...? ?else bodyn?

which when evaluated, evaluates expression test1, which if true causes body1 to be evaluated, but if false, causes test2 to be evaluated, and so on. If there is a final else clause, its bodyn part is evaluated if all of the preceding tests failed. The return result of an if statement is the result of the last body command evaluated, or the empty list if none of the bodies are evaluated.

Conditional looping is done through the while command:

     while test body

which evaluates expression test, which if true then evaluates body. It continues to do that until test evaluates to 0, and returns the empty string.

A simple example is:

     set a 10
     while {$a > 0} { puts $a; incr a -1 }

which initializes variable a with value ten and then loops printing out the value of a and decrementing it until its value is 0, when the loop terminates.

The for loop has the following form:

     for init test reinit body

which initializes the loop by executing init, then each time around the loop the expression test is evaluated, which if true causes body to be executed and then executes reinit. The loop spins around until test evaluates to 0. The return result of a for loop is the empty string.

An example of a for loop:

     for {set a 10} ($a>0) {incr a -1} {puts $a}

which initializes the variable a with value 10, then goes around the loop printing the value of a and decrementing it as long as its value is greater than 0. Once it reaches 0 the loop terminates.

The foreach command has the following form:

     foreach varName list body

where varName is the name of a variable, list is an instance of a list, and body is a series of commands to evaluate. A foreach then iterates over the elements of a list, setting the variable varName to the current element, and executes body. The result of a foreach loop is always the empty string.

An example of a foreach loop:

     foreach friend {joe mary john wilbert} {puts "I like $friend"}

will produce the output:

     I like joe
     I like mary
     I like john
     I like wilbert

There are also a couple of commands for controlling the flow of loops: continue and break.

continue stops the current evaluation of the body of a loop and goes on to the next one.

break terminates the loop altogether.

Tcl has a general switch statement, which has two forms:

     switch ?options? string pattern body ?pattern body ... ?
     switch ?options? string { pattern body ?pattern body ...? }

When executed, the switch command matches its string argument against each of the pattern arguments, and the body of the first matching pattern is evaluated. The matching algorithm depends on the options chosen, which can be one of

-exact use exact matching
-glob use glob-style matching
-regexp use regular expression matchinig

An example is:

     set a rob
     switch -glob $a {
         a*z { puts "A to Z"}
         r*b { puts "rob or rab"}
     }

which will produce the output:

     rob or rab

There are two forms of the switch command. The second form has the command arguments surrounded in curly brackets. This is primarily so that multi-line switch commands can be formed, but it also means that the arguments in brackets are not evaluated (curly brackets suppress evaluation), whereas in the first type of switch statement the arguments are first evaluated before the switch is evaluated. These effects should be borne in mind when choosing which kind of switch statement to use.

The final form of control statement is eval:

     eval arg ?arg ...?

which takes one or more arguments, concatenates them into a string, and executes the string as a command. The return result is the normal return result of the execution of the string as a command.

An example is

     set a b
     set b 0
     eval set $a 10

which results in the variable b being set to 10. In this case, the return result of the eval is 10, the result of executing the string "set b 10" as a command.

Tcl has several commands over strings. There are commands for searching for patterns in strings, formatting and parsing strings (much the same as printf and scanf in the C language), and general string manipulation commands.

Firstly we will deal with formatting and parsing of strings. The commands for this are format and scan respectively.

     format formatString ?value value ...?

which works in a similar to C's printf; given a format string with placeholders for values and a series of values, return the appropriate string.

Here is an example of printing out a table for base 10 logarithms for the numbers 1 to 10:

     for {set n 1} {$n <= 10} {incr n} {
         puts [format "log10(%d) = %.4f" $n [expr log10($n)]]
     }

which produces the output

     ln(1) = 0.0000
     ln(2) = 0.3010
     ln(3) = 0.4771
     ln(4) = 0.6021
     ln(5) = 0.6990
     ln(6) = 0.7782
     ln(7) = 0.8451
     ln(8) = 0.9031
     ln(9) = 0.9542
     ln(10) = 1.0000

The reverse function of format is scan:

     scan string formatString varName ?varName ...?

which parses the string according to the format string and assigns the appropriate values to the variables. it returns the number of fields successfully parsed.

An example,

     scan "qty 10, unit cost 1.5, total 15.0" \
          "qty %d, unit cost %f, total %f"    \
          quantity cost_per_unit total

would assign the value 10 to the variable quantity, 1.5 to the variable cost_per_unit and the value 15.0 to the variable total.

There are commands for performing two kinds of pattern matching on strings: one for matching using regular expressions, and one for matching using UNIX-style wildcard pattern matching (globbing).

The command for regular expressions matching is as follows:

     regexp ?-indices? ?-nocase? exp string ?matchVar? ?subVar subVar ...?

where exp is the regular expression and string is the string on which the matching is performed. The regexp command returns 1 if the expression matches the string, 0 otherwise. The optional -nocase switch does matching without regard to the case of letters in the string. The optional matchVar and subVar variables, if present, are set to the values of string matches. In the regular expression, a match that is to be saved into a variable is enclosed in round braces. An example is

     regexp {([0-9]+)} "I have 3 oranges" a

will assign the value 3 to the variable a.

If the optional switch -indices is present, instead of storing the matching substrings in the variables, the indices of the substrings are stored; that is a list with a pair of numbers denoting the start and end position of the substring in the string. Using the same example:

     regexp -indices {([0-9]+)} "I have 3 oranges" a

will assign the value "7 7", because the matched numeral 3 is in the eighth position in the string, and indices count from 0.

String matching using the UNIX-style wildcard pattern matching technique is done through the string match command:

     string match pattern string

where pattern is a wildcard pattern and string is the string to match. If the match succeeds, the command returns 1; otherwise, it returns 0. An example is

     string match {[a-z]*[0-9]} {a_$%^_3}

which matches because the command says match any string that starts with a lower case letter and ends with a number, regardless of anything in between.

There is a command for performing string substitutions using regular expressions:

     regsub ?-all? ?-nocase? exp string subSpec varName

where exp is the regular expression and string is the input string on which the substitution is made, subSpec is the string that is substituted for the part of the string matched by the regular expression, and varName is the variable on which the resulting string is copied into. With the -nocase switch, the matching is done without regard to the case of letters in the input string. The -all switch causes repeated matching and substitution to happen on the input string. The result of a regsub command is the number of substitutions made.

An example of string substitution is:

     regsub {#name#} {My name is #name#} Rob result

which sets the variable result to the value "My name is Rob". An example of using the -all switch:

     regsub -all {#name#} {#name#'s name is #name#} Rob result

sets the variable result to the value "Rob's name is Rob" and it returns the value 2 because two substitutions were made.

The are a host of other ways to manipulate strings through variants of the string command. Here we will go through them.

To select a character from a string given the character position, use the string index command. An example is:

     string index "Hello world" 6

which returns w, the 7th character of the string. (Strings are indexed from 0).

To select a substring of a string, given a range of indices use the string range command. An example is:

     string range "Hello world" 3 7

which returns the string "lo wo". There is a special index marker named end, which is used to denote the the end of a string, so the code

     string range "Hello world" 6 end

will return the string "world".

There are two ways to do simple search for a substring on a string, using the string first and string last commands. An example of string first is:

     string first "dog" "My dog is a big dog"

find the first position in string "My dog is a big dog" that matches "dog". It will return the position in the string in which the substring was found, in this case 3. If the substring cannot be found, the value -1 is returned.

Similarly,

     string last "dog" "My dog is a big dog"

will return the value 16 because it returns the index of the last place in the string that the substring matches. Again, if there is no match, -1 is returned.

To find the length of a string use string length, which given a string simply returns its length.

     string length "123456"

returns the value 6.

To convert a string completely to upper case use string toupper:

     string toupper "this is in upper case"

returns the string "THIS IS IN UPPER CASE".

Similarly,

     string tolower "THIS IS IN LOWER CASE"

returns the string "this is in lower case".

There are commands for removing characters from strings: string trim, string trimright, and string trimleft.

     string trim string ?chars?

which removes the characters in the string chars from the string string and returns the trimmed string. If chars is not present, whitespace characters are removed. An example is:

     string string "The dog ate the exercise book" "doe"

which would return the string "Th g at th xrcis bk".

string trimleft is the same as string trim except only leading characters are removed. Similarly string trimright removes only trailing characters. For example:

     string trimright $my_input

would return a copy of the string contained in $my_input but with all the trailing whitespace characters removed.

There is a comprehensive set of commands for file manipulation. We will cover only the some of the more important ones here.

To open a file the open command is used:

     open name ?access?

where name is a string containing the filename, and the option access parameter contains a string of access flags, in the UNIX style. The return result is a handle to the open file.

If access is not present, the access permissions default to "r", which means open for reading only. The command returns a file handle that can be used with other commands. An example of the use of the open command is

     set fid [open "myfile" "r+"]

which means open the file myfile for both reading and writing and set the variable fid to the file handle returned.

To close a file simply use

     close fileId

For example,

     close $fid

will close the file that has the file handle stored in the variable fid.

To read from a file, the read command is used:

     read fileId numBytes

which reads numBytes bytes from the file attached to file handle fileId, and returns the bytes actually read.

To read a single line from a file use gets:

     gets fileId ?varName?

which reads a line from the file attached to file handle fileId but chops off the trailing newline. If variable varName is specified, the string read in is stored there and the number of bytes is returned by the command. If the variable is not specified, the command returns the string only.

To write to a file, use puts:

     puts ?-nonewline? ?fileId? string

which outputs the string string. If the file handle fileId is present, the string is output to that file; otherwise, it is printed on stdout. If the switch -nonewline is present, a trailing newline is not output.

To check if the end of a file has been reached, use eof:

     eof fileId

which, given a file handle fileId returns 1 if the end has been reached, and 0 otherwise.

The are a host of other commands over files and processes, which we will not go into here.

(For extra information on file I/O commands, refer to the Tcl manual pages.)

Tcl provides a way of creating new commands, called procedures, that can be executed in scripts. The arguments of a procedure can be call-by-value or call-by-reference, and there is also a facility for creating new user defined control structures using procedures.

A procedure is declared using the proc command:

     proc name argList body

where the name of the procedure is name, the arguments are contained in argList and the body of the procedure is the script body. An example of a procedure is:

     proc namePrint { first family } {
         puts "My first name is $first"
         puts "My family name is $family"
     }

which can be called with

     namePrint Tony Blair

to produce the output:

     My first name is Tony
     My family name is Blair

A procedure with no arguments is specified with an empty argument list. An example is a procedure that just prints out a string:

     proc stringThing {} {
         puts "I just print this string"
     }

Arguments can be given defaults by pairing them with a value in a list. An example here is a counter procedure:

     proc counter { value { inc 1 } } {
         eval $value + $inc
     }

which can be called with two arguments like this

     set v 10
     set v [counter $v 5]

which will set variable v to the value 15; or it can be called with one argument:

     set v 10
     set v [counter $v]

in which case v will have the value 11, because the default of the argument inc inside the procedure is the value 1.

There is a special argument for handling procedures with variable number of arguments, the args argument. An example is a procedure that sums a list of numbers:

     proc sum { args } {
         set result 0;
     
         foreach n $args {
          set result [expr $result + $n ]
         }
     
         return $result;
     }

which can be called like this:

     sum 1 2 3 4 5

which returns the value 15.

The restriction on using defaulted arguments is that all the arguments that come after the defaulted ones must also be defaulted. If args are used, it must be the last argument in the argument list.

A procedure can return a value through the return command:

     return ?options? ?value?

which terminates the procedure returning value value, if specified, or just causes the procedure to return, if no value specified. (The ?options? part has to do with raising exceptions, which we will will not cover here.)

The return result of a user defined procedure is the return result of the last command executed by it.

So far we have seen the arguments of a procedure are passed using the call-by-value mechanism. They can be passed call by reference using the upvar command:

     upvar ?level? otherVar1 myVar1 ?otherVar2 myVar2 ...?

which makes accessible variables somewhere in a calling context with the current context. The optional argument level describes how many calling levels up to look for the variable. This is best shown with an example:

     set a 10
     set b 20
     
     proc add { first second } {
         upvar $first f $second s
         expr $f+$s
     }

which when called with

     add a b

will produce the result 30. If you use call-by-value instead:

     add $a $b

the program will fail because when executing the procedure add it will take the first argument 10 as the level argument, a bad level. (Also variable 20 doesn't exist at any level.)

New control structures can be generated using the uplevel command:

     uplevel ?level? arg ?arg arg ...?

which is like eval, but it evaluates its arguments in a context higher up the calling stack. How far up the stack to go is given by the optional level argument.

     proc do { loop condition } {
         set nostop 1
     
         while { $nostop } {
             uplevel $loop
             if {[uplevel "expr $condition"] == 0} {
                 set nostop 0
              }
         }
     }

which when called with this

     set x 5
     do { puts $x; incr x -1 } { $x > 0 }

will print

     5
     4
     3
     2
     1

(Please note: this doesn't quite work for all kinds of calls because of break, continue, and return. It is possible to get around these problem, but that is outside the scope of this tutorial.)

A word about the scope of variables. Variables used within procedures are normally created only for the duration of that procedure and have local scope.

It is possible to declare a variable as having global scope, through the global command:

     global name1 ? name2 ...?

where name1, name2, ..., are the names of global variables. Any references to those names will be taken to denote global variables for the duration of the procedure call.

Global variables are those variables declared at the topmost calling context. It is possible to run a global command at anytime in a procedure call. After such a command, the variable name will refer to a global variable until the procedure exits.

An example:

     set x 10
     
     proc fred { } {
         set y 20
         global x
         puts [expr $x + $y]
     }
     
     fred

will print the result 30 where 20 comes from the local variable y and 10 comes from the global variable x.

Without the global x line, the call to fred will fail with an error because there is no variable x defined locally in the procedure for the expr to evaluate over.

In common with other scripting languages, there is a command for evaluating the contents of a file in the Tcl interpreter:

     source fileName

where fileName is the filename of the file containing the Tcl source to be evaluated. Control returns to the Tcl interpreter once the file has been evaluated.


Send feedback on this subject.