Vous êtes sur la page 1sur 81

Tcl tutorial This is Tcl tutorial. In this tutorial you will learn Tcl language.

The tutorial is suitable for beginners. Table of contents Tcl language Lexical structure Basic commands Expressions Flow control Strings Lists Arrays Procedures Input/Output 1.Tcl 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 language is commonly used for rapid prototyping, scripted applications, GUIs and testing. The Tcl stands for tool command language, where the source code of a Tcl script consists of commands.

Tcl In this part of the Tcl tutorial, we will introduce the Tcl programming language. Goal The goal of this tutorial is to get you started with the Tcl programming language. The tutorial covers the core of the Tcl language. Variables, lists, arrays, control structures and other core features. It is not a complete coverage of the language. It is a quick, introductory material. The tutorial was created on Ubuntu Linux.

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. But it is often used outside its original area. The

language is commonly used for rapid prototyping, scripted applications, GUIs and testing. The Tcl stands for tool command language, where the source code of a Tcl script consists of commands. Tcl is a procedural language. It has some functional features. OOP support is planned for the next official release. The official web site for both Tcl and Tk is tcl.tk Popularity There are hundreds of programming languages in use today. Tcl does not belong to the most popular ones. It has its own niche, where it used. According to the langpop.comsite it scored 21. On tiobe index, it ended on the 96. place. Interactive interpreter We can run Tcl commands in a script or in an interactive interpreter. In this tutorial, we will use the interactive Tcl session to demonstrate some smaller code fragments. Larger code examples are to be put in Tcl scripts. $ tclsh % puts $tcl_version 8.5 % puts $tcl_interactive 1 This is an example of the Tcl interactive session. $ tclsh We start the interactive session with the tclsh command. % puts $tcl_version 8.5 The prompt changes to the % character. We print the value of a special tcl_version variable to the console. It is set to the version of the current Tcl in use. % puts $tcl_interactive 1 The tcl_interactive variable tells us whether we are in an interactive mode or not.

Tcl scripts We will have our first simple example of a Tcl script. #!/usr/bin/tclsh

# first.tcl

puts "This is Tcl tutorial" In this script, we print a message to the console. #!/usr/bin/tclsh Every script in the UNIX starts with a shebang. The shebang is the first two characters in the script: #!. The shebang is followed by the path to the interpreter, which will execute our script. The /usr/bin/ is the most common location for the Tcl shell. It could also be located in /usr/local/bin/ or elsewhere. # first.tcl Comments in Tcl are preceded by a # character. puts "This is Tcl tutorial" The puts command prints a string to the console. $ which tclsh /usr/bin/tclsh The path to the Tcl interpreter can be found using the which command. $ chmod +x first.tcl $ ./first.tcl This is Tcl tutorial We make script executable with the chmod command. And execute it. Sources The following sources were used to create this tutorial: tcl.tk wikipedia.org In this part of the Tcl tutorial, we have introduced the Tcl language.

2.Tcl lexical structure Computer languages, like human languages, have a lexical structure. A lexis of a Tcl language consists of basic elements and rules that apply to them. Words are basic elements in Tcl. Words can be either commands or command arguments. Substitution is one of the basic rules of the Tcl grammar. Commands Tcl is a string-based, interpreted command language. A Tcl script consists of commands, which are separated by newlines or semicolons. Commands are the basic execution elements. A command is followed by one or more words which are its arguments. Each argument is separated by white space. A Tcl command has the following form : command arg1 arg2 arg3 ... The Tcl interpreter takes each word of the sentence and evaluates it. The first word is considered to be the command. Most Tcl commands are variadic. This means that they can process variable number of arguments. When a Tcl script is parsed the commands are evaluated. Each command interprets words in its own context. puts "Tcl language" In the above code excerpt, we have a puts command. This command prints a message to the console. The "Tcl language" is a string, which is being printed. Unlike in other languages, strings must not be enclosed in double quotes. Unless there is a white space. #!/usr/bin/tclsh

puts zetcode.com; puts androida.co

puts zetcode puts androida In the first case the commands are separated by the semicolon (;) character. In the second case they are separated by the newline character. Substitution There are three kinds of substitutions in Tcl. Command substitution Variable substitution Backslash substitution

Square brackets are used for command substitution. % puts [expr 1+2] 3 The expr command is used to perform arithmetic calculations. First the command between the square brackets is evaluated and the result is returned to the putscommand. The puts command then evaluates the result and prints it to the console.

If a word contains a dollar sign ($), then Tcl performs variable substitution. The dollar-sign and the following characters are replaced in the word by the value of a variable. #!/usr/bin/tclsh

set name Jane

puts name puts $name We create a variable called name and set a value to it. puts name In this case, we print a string "name" to the console. puts $name In the second case, the argument is preceded by a $ character. The value of the name variable is printed to the console. $ ./name.tcl name Jane Output of the example.

With the backslash substitution, we escape the original meaning of the character. For example, the \n stands for a new line. The \t is the tab character. % puts "This is \t Sparta" This is Sparta

Here the \t sequence is replaced with a tab. #!/usr/bin/tclsh

puts "This was a \"great\" experience" puts "The \\ character is the backslash character"

puts "20000\b\b miles" We use the backslash substitution, if we want to have quotes inside quote characters. Also if we want to print the \ character, we must precede it with additional backslash. The \b is substituted with a backspace. $ ./backslash.tcl This was a "great" experience The \ character is the backslash character 200 miles Running the example. Comments Comments are used by humans to clarify the source code. In Tcl comments start with the # character. # example of a puts command puts "Tcl language" All characters after the # character are ignored by tclsh. puts "Tcl language" ; # example of a puts command Inline comments are possible only if we use a semicolon. White space White space is used to separate words in Tcl source. It is also used to improve readability of the source code. set name Jane The set command takes two parameters, which are separated by white space. set age set name 32 Robert

set occupation programmer

We might use more spaces if we want to improve the clarity of the source code. set vals { 1 2 3 4 5 6 7 } puts $vals White space is used to separate items in Tcl lists. In C based languages, we would use the comma character. Variables A variable is an identifier, which holds a value. In programming we say, that we assign/set a value to a variable. Technically speaking, a variable is a reference to a computer memory, where the value is stored. Variable names are case sensitive. This means, that Name, name or NAME refer to three different variables. Variables in Tcl are created with the set command. To obtain the value of a variable, its name is preceded with a $ character. #!/usr/bin/tclsh

set name Jane set Name Julia set NAME Erika

puts $name puts $Name puts $NAME In the above script we set three variables. The variable names are the same, they only differ in case. This practice is however not recommended. $ ./case.tcl Jane Julia Erika Output. Braces Braces {} have special meaning in Tcl. Substitution of words is disabled inside braces. #!/usr/bin/tclsh

set name {Julia Novak} puts $name

puts "Her name is $name" puts {Her name is $name} This is a small script showing a usage of the braces in Tcl. set name {Julia Novak} Braces can be used instead of double quotes to set strings separated by a white space. puts "Her name is $name" Here the variable is substituted. puts {Her name is $name} When using braces, the variable is not substituted. Everything is printed literally. $ ./braces.tcl Julia Novak Her name is Julia Novak Her name is $name Output of the braces.tcl script.

#!/usr/bin/tclsh

set numbers { 1 2 3 4 5 6 7 } puts $numbers

puts "Braces {} are reserved characters in Tcl" puts {Braces {} are reserved characters in Tcl} Braces are used to create lists. A list is a basic data type in Tcl. set numbers { 1 2 3 4 5 6 7 } Here a list of numbers is created.

puts "Braces {} are reserved characters in Tcl" puts {Braces {} are reserved characters in Tcl} Braces inside double quotes or inside other braces are taken as regular characters without special meaning. $ ./braces2.tcl
1 2 3 4 5 6 7

Braces {} are reserved characters in Tcl Braces {} are reserved characters in Tcl Output of the braces2.tcl script. Square brackets Square brackets, [], are used to create nested commands. These nested commands are executed before the main command on the Tcl source line. They are used to pass the result of one command as an argument to another command. #!/usr/bin/tclsh

set cwd [pwd] puts $cwd

puts [clock format [clock seconds] -format "%Y-%m-%d %T"] In the above code example, we show some nested commands. set cwd [pwd] The pwd command returns the current working directory of the script. It is put between the square brackets, which makes it a nested command. First the pwd command is executed and then the result of the command is set to the cwd variable. puts [clock format [clock seconds] -format "%Y-%m-%d %T"] Nested commands can be nested inside other nested commands. First the clock secondsis executed. It returns the current local time in seconds. The result is passed to the clock format command, which formats the time in a readable form. Finally, the formatted time is returned to the puts command, which prints it to the console. $ ./nested.tcl /home/vronskij/programming/tcl/lexis 2011-04-05 12:19:21

Output of the example. Quotes Double quotes group words as a single argument to commands. Dollar signs, square brackets and backslash are interpreted inside quotes. #!/usr/bin/tclsh

set distro Ubuntu puts "The Linux distribution name is $distro"

puts "The current working directory: [pwd]" puts "2000000\b\b\b miles" This is a practical example of using quotes in Tcl. puts "The Linux distribution name is $distro" The variable distro is evaluated inside the quote characters. The $distro is replaced with "Ubuntu". puts "The current working directory: [pwd]" Commands inside square brackets are interpreted too. Here we get the current working directory with the pwd command. puts "2000000\b\b\b miles" The \b escape sequence deletes a preceding character. In our case three zeros are deleted. $ ./quotes.tcl The Linux distribution name is Ubuntu The current working directory: /home/vronskij/programming/tcl/lexis 2000 miles Output of the quotes.tcl example. Backslash The backslash character can be used in three different ways in Tcl. It introduces some special characters, called escape sequences. These can be newlines, tabs, backspaces among others. It escapes the meaning of special Tcl characters ($, {}, "", \, ()). Finally, it can serve as a line continuation character.

#!/usr/bin/tclsh

puts "0\t1"

set name Jane puts \$name puts \\$name

puts "He said: \"There are plenty of them\"" puts "There are currently many Linux\ distributions in the world" The above script shows how the backslash character can be used in Tcl. puts "0\t1" The \t character has a special meaning in Tcl. It stands for a tab white space character. When we execute the script, 8 spaces are put inside 0 and 1. puts \$name With the backslash, we escape the meaning of the dollar sign. In our case $name characters are printed to the console. puts \\$name The backslash can be escaped too. Here the backslash character and the value of the name variable are printed to the console. puts "He said: \"There are plenty of them\"" We can form direct speech by escaping the meaning of the inner double quotes. puts "There are currently many Linux\ distributions in the world" If the source line is too wide, we can continue on the next line using the backslash character. Effectively escaping the newline. $ ./backslash.tcl 0 1 $name

\Jane He said: "There are plenty of them" There are currently many Linux distributions in the world Running the example. Round brackets Round brackets are used to indicate an array subscript or to change the precedence of operators for the expr command. #!/usr/bin/tclsh

set names(1) Jane set names(2) Robert

puts $names(1) puts $names(2)

puts [expr (1+3)*5] This is a simple example with round brackets in Tcl. puts $names(1) We use the round brackets to access the value by a key which is specified inside round brackets. puts [expr (1+3)*5] Here we change the precedence for operators. First 1 and 3 are added and then the result is multiplied by 5. In this chapter we have described the lexis of the Tcl language. 3.Basic commands in Tcl In this part of the Tcl tutorial, we will cover some basic Tcl commands. In the first example, we will mention the puts command. The puts command is used to print messages to the console or to other channels like a file. The command has the following syntax: puts ?-nonewline? ?channelId? string The puts is the command name. Optional parameters are specified between question marks. The nonewline switch suppresses the newline character. By default, the command puts a newline to each

message. The channelId must be an identifier for an open channel such as the Tcl standard input channel (stdin), the return value from an invocation of open or socket. It defaults to stdout, if not specified. Finally the string is the message to be printed. #!/usr/bin/tclsh

puts "This is Tcl tutorial" puts stdout "This is Tcl tutorial" The puts command prints a message to the console. Both command invocations do the same thing. #!/usr/bin/tclsh

puts [open messages w] "This is Tcl tutorial" Here we use the puts command to write to a file. We open a file for writing using the opencommand. $ cat messages This is Tcl tutorial We show the contents of the messages file created by the above Tcl script.

Greeting a user. #!/usr/bin/tclsh

puts -nonewline "What is your name? " flush stdout gets stdin name puts "Hello $name" In this example, we request an input from the user and print the input in a custom greeting. puts -nonewline "What is your name? " The -nonewline option suppresses the newline. The prompt remains on the same line. flush stdout The output is buffered. To see the output immediately after the command runs, we can use the flush command. The stdout is the standard output. In our case a terminal. It is called a channel id in Tcl. gets stdin name

The gets command reads a line from the standard input. The result is stored in the name variable. puts "Hello $name" Finally, we greet the user. $ ./name.tcl What is your name? Jan Hello Jan Running the example.

The info command returns information about the state of the Tcl interpreter. #!/usr/bin/tclsh

puts [info tclversion] puts [info host] puts [info exists var] The info command has several options. We show three of them. puts [info tclversion] Here we print the version of the Tcl interpreter. puts [info host] This line prints the host name. puts [info exists var] Finally we check if the variable var is set.

The set command is used to create and read variables. The unset command destroys a variable. #!/usr/bin/tclsh

set x 23 puts $x puts [set x]

unset x puts [info exists x] An example showing the set and unset commands. set x 23 We create an x variable and assign a value 23 to it. puts $x We print the value of the x variable. puts [set x] This line also prints the value of the x variable. The set command with one parameter reads the value of the variable. The value is passed to the puts command and printed to the terminal. unset x The variable x is destroyed. puts [info exists x] We verify the existence of the variable using the info exists command.

Tcl scripts like any other scripts can take command line arguments. Tcl has three predefined variables. $argc - the number of arguments passed to the script $argv - the list of arguments $argv0 - the name of the script #!/usr/bin/tclsh

puts "The script has $argc arguments" puts "The list of arguments: $argv" puts "The name of the script is $argv0" We use all the predefined variables in this script. $ ./args.tcl 1 2 3 The script has 3 arguments The list of arguments: 1 2 3 The name of the script is ./args.tcl

Running the example. This chapter covered some basics of the Tcl language. 4.Expressions in Tcl In this part of the Tcl tutorial, we will talk about expressions. In Tcl language the expressions are not built into the core language. Expressions are evaluated with the exprcommand. Expressions are constructed from operands and operators. The operators of an expression indicate which operations to apply to the operands. The order of evaluation of operators in an expression is determined by the precedence and associativity of the operators. An operator is a special symbol which indicates a certain process is carried out. Operators in programming languages are taken from mathematics. Programmers work with data. The operators are used to process data. An operand is one of the inputs (arguments) of an operator.

The following table shows a set of operators used in the Tcl language.
Catego ryS y mbol Sign, bit-wise, logical NOT- + ~ !Exponentiation**Arithmetic+ - * / %Shift<< >>Relational== != < > <=

>=String comparisoneq neListin niBitwise& | ^Boolean&& ||Ternary?:

An operator usually has one or two operands. Those operators that work with only one operand are called unary operators. Those which work with two operands are calledbinary operators. There is also one ternary operator (?:), which works with three operands. Basic operators Basic operators are commonly used operators. These are sign operators, arithmetic operators, modulo and exponentiation operators. #!/usr/bin/tclsh

puts [expr +2] puts [expr -2] puts [expr -(-2)] puts [expr 2+2] puts [expr 2-2] puts [expr 2*2] puts [expr 2/2] puts [expr 2/2.0]

puts [expr 2 % 2] puts [expr 2 ** 2] The above example shows usage of common operators in Tcl. puts [expr +2] In this code line we use the plus sign operator. It has no effect on the number. It merely indicates that the number is positive. It can be omitted and most of the time it is. puts [expr -2] puts [expr -(-2)] The minus operator is compulsory. It says that the number is negative. The minus operator changes the sign of the number. In the second line, the minus operator changes the -2 to positive 2. puts [expr 2+2] puts [expr 2-2] puts [expr 2*2] puts [expr 2/2] The above lines show common arithmetic operators in use. puts [expr 2 % 2] The % is the modulo or remainder operator. It finds the remainder of division of one number by another. 2 % 2, 2 modulo 2 is 0 because 2 goes into 2 once with the remainder of 0. So the code line prints zero to the console. puts [expr 2 ** 2] This is the exponentiation operator. The code line prints 4 to the console. $ ./exp.tcl 2 -2 2 4 0 4 1 1.0 0 4

Output of the example. Division operator Beginning programmers are often confused by division operation. In many programming languages there are two kinds of division operations. Integer and non-integer. This applies for the Tcl as well. % expr 3/2 1 % expr 3/2.0 1.5 Note the difference between the integer and floating point division. When at least one of the operands is a floating point number, the result is a floating point value too. The result is more exact. If both operands are integers, the result is an integer too. Assignment operator, increment operator There is no assignment operator (=) and no increment/decrement (++/--) operators in Tcl. These operators are common in other computer languages. Instead of that, Tcl has commands. % set a 5 5 % incr a 6 % incr a 7 % incr a -1 6 The above code shows what commands are used to implement the missing operators. % set a 5 In Python, we would do a = 5. In Tcl, we set a value to a variable using the set command. % incr a 6 In C, Java and many other languages, we would increment a variable by one this way:a++;. In Tcl, we use the incr command. By default, the value is incremented by 1.

% incr a -1 6 The above code shows how to decrement a variable by one, which is accomplished commonly by the (--) decrement operator in other languages. Boolean operators In Tcl, we have the following logical operators. Boolean operators are also called logical.
Sy mbol Na m e &&logical and||logical or!negation#!/usr/bin/tclsh

set x 3 set y 8

puts [expr $x == $y] puts [expr $y > $x]

if {$y > $x} {

puts

"y is greater than x"

} Many expressions result in a boolean value. Boolean values are used in conditional statements. puts [expr $x == $y] puts [expr $y > $x] Relational operators always result in a boolean value. These two lines print 0 and 1. if {$y > $x} {
puts

"y is greater than x"

} The body of the if command is executed only if the condition inside the parentheses is met. The $y > $x returns true, so the message "y is greater than x" is printed to the terminal.

#!/usr/bin/tclsh

puts [expr 0 && 0] puts [expr 0 && 1] puts [expr 1 && 0] puts [expr 1 && 1] Example shows the logical and (&&) operator. It evaluates to true only if both operands are true. $ ./andoperator.tcl 0 0 0 1

The logical or (||) operator evaluates to true, if either of the operands is true. #!/usr/bin/tclsh

puts [expr 0 || 0] puts [expr 0 || 1] puts [expr 1 || 0] puts [expr 1 || 1] If one of the sides of the operator is true, the outcome of the operation is true. $ ./oroperator.tcl 0 1 1 1

The negation operator (!) makes true false and false true. #!/usr/bin/tclsh

puts [expr ! 0] puts [expr ! 1]

puts [expr ! (4<3)] The example shows the negation operator in action. $ ./not.tcl 1 0 1

The ||, and && operators are short circuit evaluated. Short circuit evaluation means that the second argument is only evaluated if the first argument does not suffice to determine the value of the expression: when the first argument of the logical and evaluates to false, the overall value must be false; and when the first argument of logical or evaluates to true, the overall value must be true. (wikipedia) Short circuit evaluation is used mainly to improve performance. An example may clarify this a bit more. #!/usr/bin/tclsh

proc One {} {
puts

"Inside one" false

return

proc Two {} {

puts

"Inside two" true

return

puts "Short circuit"

if { [One] && [Two] } {

puts

"Pass"

puts "###################"

if { [Two] || [One] } {

puts

"Pass"

} We have two procedures in the example. (Procedures and conditionals will be described later.) They are used as operands in boolean expressions. We will see, if they are called or not. if { [One] && [Two] } {
puts

"Pass"

} The One procedure returns false. The short circuit && does not evaluate the second procedure. It is not necessary. Once an operand is false, the result of the logical conclusion is always false. Only "Inside one" is only printed to the console. puts "###################" if { [Two] || [One] } {
puts

"Pass"

} In the second case, we use the || operator and use the Two procedure as the first operand. In this case, "Inside two" and "Pass" strings are printed to the terminal. It is again not necessary to evaluate the second operand, since once the first operand evaluates to true, the logical or is always true. $ ./shortcircuit.tcl Short circuit Inside one ################### Inside two Pass

Result of the shorcircuit.tcl script. Relational Operators Relational operators are used to compare values. These operators always result in boolean value. In Tcl 0 stands for false and 1 for true. Relational operators are also called comparison operators.
Sy mbol Me ani ng <less than<=less than or equal to>greater than>=greater than or equal to==equal to!=not equal

to#!/usr/bin/tclsh

puts [expr 3 < 4] puts [expr 3 == 4] puts [expr 4 >= 3] puts [expr 4 != 3] In Tcl we use the == to compare numbers. Some languages like Ada, Visual Basic, or Pascal use = for comparing numbers. $ ./rel.tcl 1 0 1 1 The example prints four boolean values. Bitwise operators Decimal numbers are natural to humans. Binary numbers are native to computers. Binary, octal, decimal or hexadecimal symbols are only notations of the same number. Bitwise operators work with bits of a binary number. Bitwise operators are seldom used in higher level languages like Tcl.
Sy mbol Me ani ng ~bitwise negation^bitwise exclusive or&bitwise and|bitwise orThe

bitwise negation

operator changes each 1 to 0 and 0 to 1. % puts [expr ~7] -8 % puts [expr ~-8] 7

The operator reverts all bits of a number 7. One of the bits also determines, whether the number is negative or not. If we negate all the bits one more time, we get number 7 again. The bitwise and operator performs bit-by-bit comparison between two numbers. The result for a bit position is 1 only if both corresponding bits in the operands are 1.
00110 & =

00011 00010

The first number is a binary notation of 6. The second is 3. The result is 2. % puts [expr 6 & 3] 2 % puts [expr 3 & 6] 2 The bitwise or operator performs bit-by-bit comparison between two numbers. The result for a bit position is 1 if either of the corresponding bits in the operands is 1.
00110 |

00011

= 00111

The result is 00110 or decimal 7. % puts [expr 6 | 3] 7 % puts [expr 3 | 6] 7 The bitwise exclusive or operator performs bit-by-bit comparison between two numbers. The result for a bit position is 1 if one or the other (but not both) of the corresponding bits in the operands is 1.
00110 ^ =

00011 00101

The result is 00101 or decimal 5. % puts [expr 6 ^ 3] 5 % puts [expr 3 ^ 6] 5

Operator precedence The operator precedence tells us which operators are evaluated first. The precedence level is necessary to avoid ambiguity in expressions. What is the outcome of the following expression? 28 or 40?
3 + 5 * 5

Like in mathematics, the multiplication operator has a higher precedence than addition operator. So the outcome is 28. (3 + 5) * 5 To change the order of evaluation, we can use parentheses. Expressions inside parentheses are always evaluated first. The following table shows common Tcl operators ordered by precedence (highest precedence first):
Catego ryS y mbolAsso ciati vity Sign, bit-wise, logical NOT- + ~ !LeftExponentiation**LeftArithmetic+ - * / %LeftShift<<

>>LeftRelational== != < > <= >=LeftString comparisoneq neLeftListin niLeftBitwise& | ^LeftBoolean&& || LeftTernary?:RightOperators on

the same row of the table have the same precedence.

!/usr/bin/tclsh

puts [expr 3 + 5 * 5] puts [expr (3 + 5) * 5]

puts [expr ! 1 || 1] puts [expr ! (1 || 1)] In this code example, we show some common expressions. The outcome of each expression is dependent on the precedence level. puts [expr 3 + 5 * 5] This line prints 28. The multiplication operator has a higher precedence than addition. First the product of 5*5 is calculated. Then 3 is added. puts [expr (3 + 5) * 5] Round brackets can be used to change the precedence level. In the above expression, number 3 is added to 5 and the result is multiplied by 5. puts [expr ! 1 || 1]

In this case, the negation operator has a higher precedence. First, the first true (1) value is negated to false (0), than the || operator combines false and true, which gives true in the end. $ ./precedence.tcl 28 40 1 0 Output. Associativity Sometimes the precedence is not satisfactory to determine the outcome of an expression. There is another rule called associativity. The associativity of operators determines the order of evaluation of operators with the same precedence level. 9/3*3 What is the outcome of this expression? 9 or 1? The multiplication, deletion and the modulo operator are left to right associated. So the expression is evaluated this way: (9 / 3) * 3 and the result is 9. Arithmetic, boolean, relational and bitwise operators are all left to right associated. The ternary operator is right associated. The ternary operator The ternary operator (?:) is a conditional operator. It is a convenient operator for cases, where we want to pick up one of two values, depending on the conditional expression. cond-exp ? exp1 : exp2 If cond-exp is true, exp1 is evaluated and the result is returned. If the cond-exp is false, exp2 is evaluated and its result is returned. #!/usr/bin/tclsh

set age 32 set adult [expr $age >= 18 ? true : false]

puts "Adult: $adult"

In most countries the adulthood is based on your age. You are adult if you are older than a certain age. This is a situation for a ternary operator. set adult [expr $age >= 18 ? true : false] First the expression on the right side of the assignment operator is evaluated. The first phase of the ternary operator is the condition expression evaluation. So if the age is greater or equal to 18, the value following the ? character is returned. If not, the value following the : character is returned. The returned value is then assigned to the adult variable. $ ./ternary.tcl Adult: true A 32 years old person is adult. Calculating prime numbers We are going to calculate prime numbers. Some of the features (lists, loops) will be covered later in the tutorial. #!/usr/bin/tclsh

set nums { 1 2 3 4 5 6 7 8 9 10 11 12 13 14
15 16 17 18 19 20 21 22

23 24

puts "Prime numbers"

foreach num $nums {

if {

$num==1 || $num==2 || $num==3 } {

puts

-nonewline "$num "

continue }

set i

[expr int(sqrt($num))]

set isPrime true

while { $i > 1 }

if {

$num % $i == 0 } {

set isPrime false }

incr i }

-1

if {

$isPrime } {

puts }

-nonewline "$num "

puts "" In the above example, we deal with many various operators. A prime number (or a prime) is a natural number that has exactly two distinct natural number divisors: 1 and itself. We pick up a number and divide it by numbers, from 1 up to the picked up number. Actually, we don't have to try all smaller numbers, we can divide by numbers up to the square root of the chosen number. The formula will work. We use the remainder division operator. set nums { 1 2 3 4 5 6 7 8 9 10 11 12 13 14
15 16 17 18 19 20 21 22

23 24

} We will calculate primes from this list of numbers. if { $num==1 || $num==2 || $num==3 } {
puts

-nonewline "$num "

continue

We skip the calculations for the 1, 2, 3 numbers. They are primes. Note the usage of the equality and conditional or operators. The == has a higher precedence than the || operator. So we don't need to use parentheses. set i [expr int(sqrt($num))] We are OK if we only try numbers smaller than the square root of a number in question. while { $i > 1 } {
if {

$num % $i == 0 } {

set isPrime false }

incr i

-1

} This is a while loop. The i is the calculated square root of the number. We use the incrcommand to to decrease the i by one each loop cycle. When the i is smaller than 1, we terminate the loop. For example, we have number 9. The square root of 9 is 3. We will divide the 9 number by 3 and 2. This is sufficient for our calculation. if { $isPrime } {
puts

-nonewline "$num "

} This is the core of the algorithm. If the remainder division operator returns 0 for any of the i values, than the number in question is not a prime. $ ./prime.tcl Prime numbers 1 2 3 5 7 11 13 17 19 23 Output of the script. In this part of the Tcl tutorial, we covered expressions.

5.Flow control in Tcl In this part of the Tcl tutorial, we will talk about the flow control. We will define several commands that enable us to control the flow of a Tcl script.

In Tcl language there are several commands that are used to alter the flow of the program. When the program is run, the commands are executed from the top of the source file to the bottom. One by one. This flow can be altered by specific commands. Commands can be executed multiple times. Some commands are conditional. They are executed only if a specific condition is met. The if command The if command has the following general form: if expr1 ?then? body1 elseif expr2 ?then? body2 elseif ... ?else? ?bodyN? The if command is used to check if an expression is true. If it is true, a body of command(s) is then executed. The body is enclosed by curly brackets. The if command evaluates an expression. The expression must return a boolean value. In Tcl, 1, yes, true mean true and 0, no, false mean false. !/usr/bin/tclsh

if yes {
puts

"This message is always shown"

} In the above example, the body enclosed by { } characters is always executed. #!/usr/bin/tclsh

if true then {
puts

"This message is always shown"

} The then command is optional. We can use it if we think, it will make the code more clear.

We can use the else command to create a simple branch. If the expression inside the square brackets following the if command evaluates to false, the command following theelse command is automatically executed. #!/usr/bin/tclsh

set sex female

if {$sex == "male"} {

puts

"It is a boy"

} else {

puts

"It is a girl"

} We have a sex variable. It has "female" string. The boolean expression evaluates to false and we get "It is a girl" in the console. $ ./girlboy.tcl It is a girl We can create multiple branches using the elseif command. The elseif command tests for another condition, if and only if the previous condition was not met. Note, that we can use multiple elseif commands in our tests. #!/usr/bin/tclsh

# nums.tcl

puts -nonewline "Enter a number: " flush stdout set a [gets stdin]

if {$a < 0} {

puts

"the number is negative"

} elseif { $a == 0 } {

puts

"the numer is zero"

} else {

puts

"the number is positive"

} In the above script we have a prompt to enter a value. We test the value. If it is a negative number or positive or if it equals to zero. If the first expression evaluates to false, the second expression is evaluated. If the previous conditions were not met, than the body following the else command would be executed. $ ./nums.tcl Enter a number: 2 the number is positive $ ./nums.tcl Enter a number: 0 the numer is zero $ ./nums.tcl Enter a number: -3 the number is negative Running the example multiple times. The switch command The switch command matches its string argument against each of the pattern arguments in order. As soon as it finds a pattern that matches string it evaluates the following body argument by passing it recursively to the Tcl interpreter and returns the result of that evaluation. If the last pattern argument is default then it matches anything. If no pattern argument matches string and no default is given, then the switch command returns an empty string. #!/usr/bin/tclsh

puts -nonewline "Select a top level domain name " flush stdout

gets stdin domain

switch $domain {
us

{ puts "United States" } }

de { puts Germany sk { hu

puts Slovakia }

{ puts Hungary }

default { puts

unknown }

} In our script, we prompt for a domain name. There are several options. If the value equals for example to us the "United States" string is printed to the console. If the value does not match to any given value, the default body is executed and unknown is printed to the console. $ ./switch.tcl Select a top level domain name sk Slovakia We have entered sk string to the console and the program responded with Slovakia. The while command The while command is a control flow command that allows code to be executed repeatedly based on a given boolean condition. The while command executes the commands inside the block enclosed by the curly brackets. The commands are executed each time the expression is evaluated to true. #!/usr/bin/tclsh

# whileloop.tcl

set i 0 set sum 0

while { $i < 10 } {

incr i incr sum

$i

puts $sum In the code example, we calculate the sum of values from a range of numbers. The while loop has three parts. Initialization, testing and updating. Each execution of the command is called a cycle.

set i 0 We initiate the i variable. It is used as a counter. while { $i < 10 } { ... } The expression inside the square brackets following the while command is the second phase, the testing. The commands in the body are executed, until the expression is evaluated to false. incr i The last, third phase of the while loop. The updating. We increment the counter. Note that improper handling of the while loops may lead to endless cycles. The for command When the number of cycles is know before the loop is initiated, we can use the forcommand. In this construct we declare a counter variable, which is automatically increased or decreased in value during each repetition of the loop. #!/usr/bin/tclsh

for {set i 0} {$i < 10} {incr i} {


puts

$i

} In this example, we print numbers 0..9 to the console. for {set i 0} {$i < 10} {incr i} {
puts

$i

} There are three phases. First, we initiate the counter i to zero. This phase is done only once. Next comes the condition. If the condition is met, the command inside the for block is executed. Then comes the third phase; the counter is increased. Now we repeat the 2, 3 phases until the condition is not met and the for loop is left. In our case, when the counter i is equal to 10, the for loop stops executing. The foreach command

The foreach command simplifies traversing over collections of data. It has no explicit counter. The foreach command goes throught the list one by one and the current value is copied to a variable defined in the construct. #!/usr/bin/tclsh

set planets { Mercury Venus Earth Mars Jupiter Saturn


Uranus

Neptune }

foreach planet $planets {


puts

$planet

} In this example, we use the foreach command to go through a list of planets. foreach planet $planets {
puts

$planet

} The usage of the foreach command is straightforward. The planets is the list, that we iterate through. The planet is the temporary variable, that has the current value from the list. The foreach command goes through all the planets and prints them to the console. $ ./planets.tcl Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Running the above Tcl script gives this output.

#!/usr/bin/tclsh

set actresses { Rachel Weiss Scarlett Johansson Jessica Alba \


Marion

Cotillard Jennifer Connelly}

foreach {first second} $actresses {


puts

"$first $second"

} In this script, we iterate througn pairs of values of a list. foreach {first second} $actresses {
puts

"$first $second"

} We pick two values from the list at each iteration. $ ./actresses.tcl Rachel Weiss Scarlett Johansson Jessica Alba Marion Cotillard Jennifer Connelly Output of actresses.tcl.

#!/usr/bin/tclsh

foreach i { one two three } item {car coins rocks} {


puts

"$i $item"

} We can iterate over two lists in parallel. $ ./parallel.tcl one car two coins three rocks Output. The break, continue commands The break command can be used to terminate a block defined by while, for or switchcommands.

#!/usr/bin/tclsh

while true {

set r [expr 1 + round(rand()*30)] puts

-nonewline "$r "

if {$r == 22} {

break }

puts "" We define an endless while loop. We use the break command to get out of this loop. We choose a random value from 1 to 30. We print the value. If the value equals to 22, we finish the endless while loop. set r [expr 1 + round(rand()*30)] Here we calculate a random number between 1..30. The rand() is a built-in Tcl procedure. It returns a random number from 0 to 0.99999. The rand()*30 returns a random number between 0 to 29.99999. The round() procedure rounds the final number. $ ./breakcommand.tcl 28 20 8 8 12 22 We might get something like this.

The continue command is used to skip a part of the loop and continue with the next iteration of the loop. It can be used in combination with for and while commands. In the following example, we will print a list of numbers, that cannot be divided by 2 without a remainder. #!/usr/bin/tclsh

set num 0

while { $num < 100 } {

incr num

if {$num puts

% 2 == 0} { continue }

"$num "

puts "" We iterate through numbers 1..99 with the while loop. if {$num % 2 == 0} { continue } If the expression num % 2 returns 0, the number in question can be divided by 2. Thecontinue command is executed and the rest of the cycle is skipped. In our case, the last command of the loop is skipped and the number is not printed to the console. The next iteration is started. In this part of the Tcl tutorial, we were talking about control flow structures.

6.Strings in Tcl In this part of the Tcl tutorial, we will work with string data in more detail. String is an important data type in computer languages. A string is a sequence of characters. String in Tcl, unlike in other languages, may not be enclosed within double quotes. They are necessary only if we have a space between words. Tcl is a string based language. It provides a rich set of commands for manipulating strings. First example A simple example showing some strings follows. #!/usr/bin/tclsh

puts Tcl puts Java puts Falcon

puts "Tcl language"

puts {Tcl language} The script prints some string values to the console. puts Tcl puts Java puts Falcon Strings in Tcl may not be enclosed within quotes. puts "Tcl language" puts {Tcl language} Strings in Tcl can be grouped with double quotes or curly brackets. $ ./simple.tcl Tcl Java Falcon Tcl language Tcl language Output. Using quotes What if we wanted to display quotes, for example in a direct speech? In such a case, inner quotes must be escaped. $ cat directspeech.tcl #!/usr/bin/tclsh

puts "There are many stars" puts "He said, \"Which one is your favourite?\"" We use the (\) character to escape additional quotes. $ ./directspeech.tcl There are many stars He said, "Which one is your favourite?" Output.

Multiline strings It is very easy to create a multiline string in Tcl. I many other languages creating multiline strings is much less convenient. #!/usr/bin/tclsh

set lyrics "I cheated myself like I knew I would I told ya, I was trouble you know that I'm no good"

puts $lyrics We simple continue on the next line. This is useful if we wanted to display verses. $ ./multiline.tcl I cheated myself like I knew I would I told ya, I was trouble you know that I'm no good

Comparing strings Basic comparison of strings can be done with the string compare command. #!/usr/bin/tclsh

puts [string compare 12 12] puts [string compare Eagle Eagle] puts [string compare Eagle eagle] puts [string compare -nocase Eagle eagle] The string compare command compares strings character by character. If it finds that the first characters of both strings are equal, it continues with the second character. Until the end. It returns 0, if the strings are equal. -1 if a character in the first string is located in the ascii table before the character of the second string. 1 if the character of the first string is located after the character of the second string. puts [string compare 12 12]

In this context, 12 is a string. puts [string compare Eagle Eagle] Two strings are equal, 0 is printed to the console. puts [string compare Eagle eagle] E stands before e, -1 is returned. puts [string compare -nocase Eagle eagle] With the -nocase option, we ignore the case. The two strings are equal. $ ./compare.tcl 0 0 -1 0 Output of the program.

The string equal also can be used to compare strings. The command returns 1, if the strings are equal, and 0 if they are not. #!/usr/bin/tclsh

set str1 Tcl set str2 "Tcl language"

puts [string compare $str1 $str2] puts [string compare -length 3 $str1 $str2]

puts [string equal $str1 $str2] puts [string equal -length 3 $str1 $str2] The script shows both commands comparing strings. puts [string compare $str1 $str2]

The line prints -1. The characters on the first three positions are equal. On the fourth position the string compare command compares white space with the l character. The space is located before the l character in the ascii table. Strings are not equal. puts [string compare -length 3 $str1 $str2] In this case, we limit the comparing to first three characters. They are same in both strings, so the command returns 0. puts [string equal $str1 $str2] The two strings are not identical, so the string equal command returns 0, for false. puts [string equal -length 3 $str1 $str2] Limiting strings to the first three characters, the command returns 1. Which means, they are identical up to the first three characters. Unicode We can use unicode strings in our Tcl scripts. #!/usr/bin/tclsh

puts "La femme vit par le sentiment, l o l'homme vit par l'action" puts " " We print two messages to the terminal. The first is in French, the second in Russian. $ ./unicode.tcl La femme vit par le sentiment, l o l'homme vit par l'action Output. String commands Tcl has useful built-in commands that can be used for working with strings. #!/usr/bin/tclsh

set str Eagle

puts [string length $str]

puts [string index $str 0] puts [string index $str end]

puts [string range $str 1 3] We define a string variable and work with some string commands. puts [string length $str] The string length returns the number of characters in the string. puts [string index $str 0] puts [string index $str end] The string index command returns the character at a specific position. puts [string range $str 1 3] The string range returns a range of characters, selected by the first and last index. $ ./strings1.tcl 5 E e agl Output.

We have a split command to split strings at a specific character. The command returns a list of words. These words can be combined together into a string with the joincommand. #!/usr/bin/tclsh

set langs "Tcl,Java,C,C#,Ruby,Falcon"

puts [split $langs ,] puts [join [split $langs ","] ":"] In our program, we will split and join strings.

set langs "Tcl,Java,C,C#,Ruby,Falcon" This is a string we are going to split. There are several words separated by a comma character. The comma character is the character, by which we will split the string. puts [split $langs ,] The line prints all words that we have split from the string. puts [join [split $langs ","] ":"] The split command returns a list of words from the string. These words are then joined. The words will be now separated by the colon. $ ./splitjoin.tcl Tcl Java C C# Ruby Falcon Tcl:Java:C:C#:Ruby:Falcon Output of the example.

Next we will have another example with a few string commands. #!/usr/bin/tclsh

set str "ZetCode"

puts [string toupper $str] puts [string tolower $str] puts [string totitle $str] puts [string reverse $str] We introduce four string commands. The commands do not change the original string. They return a new, modified string. puts [string toupper $str] We convert the characters to uppercase. puts [string tolower $str] We convert letters of the string to lowercase. puts [string totitle $str]

The string totitle returns a string with the first character in uppercase; other characters are in lowercase. puts [string reverse $str] We reverse the characters of the string with the string reverse command. $ ./strings2.tcl ZETCODE zetcode Zetcode edoCteZ Running the program. Formatting strings The very basic formatting of strings is done within the quotes. #!/usr/bin/tclsh

set oranges 2 set apples 4 set bananas 3

puts "There are $oranges oranges, $apples apples and\ $bananas bananas. " Tcl evaluates variables in double quotes. puts "There are $oranges oranges, $apples apples and\ $bananas bananas. " In this code line, we combine variables and strings in one sentence. $ ./fruit.tcl There are 2 oranges, 4 apples and 3 bananas. Output.

More advanced formatting can be done with the format command. It has the following synopsis. format formatString ?arg arg ...?

The formatString is used to control, how the arguments are going to be displayed. The command can take multiple arguments. #!/usr/bin/tclsh

puts [format %s "Inception movie"] puts [format "%d %s" 23 songs] This is basic script showing the usage of the format command. puts [format %s "Inception movie"] This line simply prints a string to the console. puts [format "%d %s" 23 songs] Here we print two arguments. Each argument has a format specifier, which begins with the % character. $ ./basicformat.tcl Inception movie 23 songs Output.

Now we show some basic conversion specifiers for the format command. %s, %f, %d, %e are conversion types. They control how the value is displayed. Conversion type is the only mandatory part of the conversion specifier. #!/usr/bin/tclsh

puts [format "%s" "Tcl language"] puts [format "%f" 212.432] puts [format "%d" 20000] puts [format "%e" 212.342] We will print four messages to the terminal. puts [format "%s" "Tcl language"] The %s is a conversion type for the string. puts [format "%f" 212.432]

%f is used to display decimal numbers. puts [format "%d" 20000] To print an integer value, we use the %d conversion type. puts [format "%e" 212.342] The %e is used to show number in a scientific format. $ ./format.tcl Tcl language 212.432000 20000 2.123420e+02 Output.

In the next example, we will be formatting numbers in three different number formats. #!/usr/bin/tclsh

puts [format "%-10s %-14s %s" Decimal Hexadecimal Octal]

puts [format "%-10d %-14x %o" 5000 5000 5000] puts [format "%-10d %-14x %o" 344 344 344] puts [format "%-10d %-14x %o" 55 55 55] puts [format "%-10d %-14x %o" 9 9 9] puts [format "%-10d %-14x %o" 15666 15666 15666] We print numbers in a decimal, hexadecimal and octal format. We also align the numbers in three columns. puts [format "%-10d %-14x %o" 5000 5000 5000] The %-10d applies for the first number, %-14x for the second and %o for the third. We will describe the first one. The format specifier begins with the % character. The minus sign (-) tells, that if the value will be shorter than the field width, it is left justified. The rest of the field is padded with white space. The number (10) specifies the field width. Finally the d character tells that the number is displayed in decimal format. The x stands for hexadecimal and o for octal. $ ./numbers.tcl Decimal Hexadecimal Octal

5000 344 55 9 15666 9

1388 158 37 3d32 11 67

11610 530

36462

Running the example.

Finally, we will format date and time data. We use the clock format command. #!/usr/bin/tclsh

set secs [clock seconds]

puts "Short date: [clock format $secs -format %D]" puts "Long date: [clock format $secs -format "%A, %B %d, %Y"]" puts "Short time: [clock format $secs -format %R]" puts "Long time: [clock format $secs -format %r]" puts "Month: [clock format $secs -format %B]" puts "Year: [clock format $secs -format %Y]" The preceding example demonstrates some common date and time formats. set secs [clock seconds] We get the current timestamp in seconds. This value is later passed to the clock formatcommand, to get dates and times readable for humans. puts "Short date: [clock format $secs -format %D]" The format of the date is controlled with the -format option. There are several specifiers. The %D returns a date in month/day/year format. $ ./clockformat.tcl Short date: 04/11/2011 Long date: Monday, April 11, 2011 Short time: 11:30 Long time: 11:30:30 am Month: April Year: 2011

Output. This part of the Tcl tutorial covered strings.

7.Tcl lists In this part of the Tcl tutorial, we will talk about lists. Computer programs work with data. Spreadsheets, text editors, calculators or chat clients. Working with groups of data is a basic programming operation. In Tcl, the list is a basic data structure. It is an ordered collection of items. Items in lists are separated by white space.

Every item of the list is identified by its index. Lists do not have a fixed length. List elements can be strings, numbers, variables, files or other lists. We can nest lists into other lists to any depth. Creating lists There are several ways, how we can create lists in Tcl. #!/usr/bin/tclsh

set l1 { 1 2 3 } set l2 [list one two three] set l3 [split "1.2.3.4" .]

puts $l1 puts $l2 puts $l3 We create tree lists and print their contents to the console. set l1 { 1 2 3 } The basic way to create a list is to put elements of the list inside the brackets. List elements are separated by space. set l2 [list one two three] Another way to create a list is to use the list command. set l3 [split "1.2.3.4" .]

Some Tcl commands return a list as a result. In the above code line, the split command returns a list of numbers generated from a string. $ ./createlists.tcl
1 2 3

one two three 1234 Output of the createlists.tcl script. Basic list operations In this section, we introduce some basic operations on lists. We will mention tree commands, that operate on Tcl lists. #!/usr/bin/tclsh

set nums { 1 2 3 4 5 6 7 }

puts [llength $nums] puts [lindex $nums 2] puts [lindex $nums 4] puts [lrange $nums 1 3] The script defines a list of numbers. We perform some operations on the list with specific list commands. puts [llength $nums] The llength command returns a length of the list. puts [lindex $nums 2] The lindex command returns an item on the third position of the list. The positions in Tcl lists start from 0. puts [lrange $nums 1 3] The lrange command returns a subset of the list. $ ./basicoperations.tcl 7 3 5 234

Output. Traversing lists Now that we have defined lists and basic list operations, we want to go traverse the list elements. We show several ways how to go through the list items. #!/usr/bin/tclsh

foreach item {1 2 3 4 5 6 7 8 9} {

puts

$item

} We go through list elements with the foreach command. foreach item {1 2 3 4 5 6 7 8 9} {


puts

$item

} Each loop cycle the item variable has a value from the list of numbers. $ ./traverse1.tcl 1 2 3 4 5 6 7 8 9 Ouput.

In the second example we will go through items of the days list using the while loop. #!/usr/bin/tclsh

set days [list Monday Tuesday Wednesday Thursday \


Friday

Saturday Sunday]

set n [llength $days]

set i 0

while {$i < $n} {

puts

[lindex $days $i]

incr i

} We traverse the list using a while loop. When working with a while loop, we also need a counter and a number of items in the list. set days [list Monday Tuesday Wednesday Thursday \
Friday

Saturday Sunday]

We create a list of days. set n [llength $days] The length of the list is determined with the llength command. set i 0 The is a counter. while {$i < $n} {
puts

[lindex $days $i]

incr i

} The while loop executes the commands in the body, until the counter is equal to the number of elements in the list. puts [lindex $days $i] The lindex returns a value from the list pointed to by the counter. incr i

The counter is increased. $ ./traverse2.tcl Monday Tuesday Wednesday Thursday Friday Saturday Sunday Output. List operations Now we will have some other list commands. #!/usr/bin/tclsh

set nums {4 5 6} puts $nums

lappend nums 7 8 9 puts $nums

puts [linsert $nums 0 1 2 3] puts $nums We have a list of three numbers. lappend nums 7 8 9 The lappend appends data to the list. puts [linsert $nums 0 1 2 3] The linsert inserts elements at a given index. The first number is the index. The remaining values are numbers to be inserted into the list. The command creates a new lists and returns it. It does not modify the original list. $ ./operations.tcl 456

456789 123456789 456789 This is the output of the operations.tcl script.

In the following example, we will concatenate lists, search for items and replace items in lists. #!/usr/bin/tclsh

set animals1 { lion eagle elephant dog cat } set animals2 { giraffe tiger horse dolphin }

set animals [concat $animals1 $animals2]

puts $animals

puts [lsearch -exact $animals eagle] puts [lreplace $animals 3 4 buffalo crocodile] We define two animal lists. We introduce three new commands. set animals [concat $animals1 $animals2] The concat command is used to concatenate (add) two lists. The above line joins two lists and the new list is set to the animals variable. puts [lsearch -exact $animals eagle] With the lsearch command we look for an eagle in the list. With the -exact option we look for an exact match. The command returns the index of the first matching element. Or -1 if there is no match. puts [lreplace $animals 3 4 buffalo crocodile] The lreplace command replaces dog and cat with buffalo and crocodile. $ ./operations2.tcl lion eagle elephant dog cat giraffe tiger horse dolphin 1 lion eagle elephant buffalo crocodile giraffe tiger horse dolphin

Example output. Sorting items In this section, we will show how we can sort items in Tcl lists. #!/usr/bin/tclsh

set names { John Mary Lenka Veronika Julia Robert } set nums { 1 5 4 3 6 7 9 2 11 0 8 2 3 }

puts [lsort $names] puts [lsort -ascii $names] puts [lsort -ascii -decreasing $names] puts [lsort -integer -increasing $nums] puts [lsort -integer -decreasing $nums] puts [lsort -integer -unique $nums] 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. set names { John Mary Lenka Veronika Julia Robert } set nums { 1 5 4 3 6 7 9 2 11 0 8 2 3 } We have two lists. In the first we have strings, in the second numbers. puts [lsort $names] puts [lsort -ascii $names] The default sorting is the ascii sorting. The elements are sorted by their positions in the ascii table. puts [lsort -integer -increasing $nums] puts [lsort -integer -decreasing $nums] We treat the values as integers and sort them in increasing and decreasing orders. puts [lsort -integer -unique $nums] We sort the elements of the list in a numerical context in increasing order. Duplicates will be removed. $ ./sorting.tcl John Julia Lenka Mary Robert Veronika

John Julia Lenka Mary Robert Veronika Veronika Robert Mary Lenka Julia John 0 1 2 2 3 3 4 5 6 7 8 9 11 11 9 8 7 6 5 4 3 3 2 2 1 0 0 1 2 3 4 5 6 7 8 9 11 Output. Nested lists In Tcl there can be nested lists; list in other lists. #!/usr/bin/tclsh set nums {1 2 {1 2 3 4} {{1 2} {3 4}} 3 4} puts [llength $nums] puts [llength [lindex $nums 2]] puts [lindex $nums 0] puts [lindex [lindex $nums 2] 1] puts [lindex [lindex [lindex $nums 3] 1] 1] This is a simple example with nested lists in Tcl. set nums {1 2 {1 2 3 4} {{1 2} {3 4}} 3 4} A list with two nested lists. The second list has two additional inner nested lists. puts [llength $nums] We determine the size of the list. The nested list is counted as one element. puts [llength [lindex $nums 2]] In this line, we determine the size of the first nested list, which is the third element of the main list. puts [lindex $nums 0] Here we print the first element of the main list. puts [lindex [lindex $nums 2] 1] In the above line, we get the second element of the first nested list.

puts [lindex [lindex [lindex $nums 3] 1] 1] Here we get the second element of the second inner list of the inner list located at the 4th position of the main list. In other words: the inner most command is executed first. The [lindex $nums 3] returns {{1 2} {3 4}}. Now the second command operates on this returned list. [lindex {{1 2} {3 4}} 1] returns {3 4}. Finally, the last command [lindex {3 4} 1]returns 4, which is printed to the terminal. $ ./nestedlists.tcl 6 4 1 2 4 Output. In this part of the Tcl tutorial, we covered Tcl lists. 8.Arrays in Tcl In this part of the Tcl programming tutorial, we will cover arrays. We will initiate arrays and read data from them. An array in Tcl is a data structure, which binds a key with a value. A key and a value can be any Tcl string. #!/usr/bin/tclsh

set names(1) Jane set names(2) Tom set names(3) Elisabeth set names(4) Robert set names(5) Julia set names(6) Victoria

puts [array exists names] puts [array size names]

puts $names(1) puts $names(2) puts $names(6)

We create a names array. The numbers are keys and the names are values of the array. set names(1) Jane In this line we set a value Jane to the array key 1. We can later refer to the value by the key. puts [array exists names] The array exists command determines, whether the array is created. Returns 1 if true, 0 otherwise. puts [array size names] We get the size of the array with the array size command. puts $names(1) We access a value from the array by its key. $ ./names.tcl 1 6 Jane Tom Victoria Output.

Arrays can be initiated with the array set command. #!/usr/bin/tclsh

array set days {


1 Monday 2 Tuesday 3 Wednesday 4 Thursday 5 Friday 6 Saturday 7 Sunday

foreach {n day} [array get days] {

puts

"$n -> $day"

} We create a day array. It has 7 keys and values. foreach {n day} [array get days] { The array get command returns a list of key, value elements, which can be iterated with the foreach command. $ ./days.tcl 4 -> Thursday 5 -> Friday 1 -> Monday 6 -> Saturday 2 -> Tuesday 7 -> Sunday 3 -> Wednesday Output.

We show another way to traverse an array in Tcl. #!/usr/bin/tclsh

array set nums { a 1 b 2 c 3 d 4 e 5 }

puts [array names nums]

foreach n [array names nums] {

puts

$nums($n)

} The script uses the array names command to traverse the array. array set nums { a 1 b 2 c 3 d 4 e 5 }

We define a simple array. puts [array names nums] The array names returns a list containing the names of all of the elements in the array. foreach n [array names nums] {
puts

$nums($n)

} We use the keys to get the values. $ ./getnames.tcl deabc 4 5 1 2 3 Output.

In the last example of this chapter, we will show how to remove elements from the array. #!/usr/bin/tclsh

set names(1) Jane set names(2) Tom set names(3) Elisabeth set names(4) Robert set names(5) Julia set names(6) Victoria

puts [array size names] unset names(1) unset names(2)

puts [array size names] We create a names array. We use the unset command to remove items from the array. We check the size of the array before and after we remove the two items. set names(1) Jane The set command is used to create an item in the array. unset names(1) We use the unset command to remove an element with key 1 from the array. In this part of the Tcl tutorial, we worked with arrays.

10.Procedures in Tcl In this part of the tutorial, we will cover Tcl procedures. A procedure is a code block containing a series of commands. Procedures are called functions in some programming languages. It is a good programming practice that procedures do only one specific task. Procedures bring modularity to programs. Proper use of procedures bring the following advantages: Reducing duplication of code Decomposing complex problems into simpler pieces Improving clarity of the code Reuse of code Information hiding There are two basic types of procedures. Built-in procedures and user defined ones. The built-in procedures are part of the Tcl core language. Examples are: rand(), sin() or exp(). The user defined functions are functions created with the proc keyword. The term procedures and commands are often used interchangeably. In other words, the proc keyword is used to create new Tcl commands. We start with a simple example. #!/usr/bin/tclsh

proc tclver {} {

set v [info tclversion] puts

"this is tcl version $v"

tclver In this script, we create a simple tclver procedure. The procedure prints the version of Tcl language. proc tclver {} { The new procedure is created with the proc command. The {} characters tell us, that the procedure takes no arguments.
{

set v [info tclversion] puts

"this is tcl version $v"

} This is the body of the tclver procedure. It is executed, when we execute the tclver command. The body of the command lies between the curly brackets. tclver The procedure is called by specifying its name. $ ./version.tcl this is tcl version 8.5 Sample output. Procedure arguments An argument is a value passed to the procedure. Procedures can take one or more arguments. If procedures work with data, we must pass the data to the procedures. In the following example, we have a procedure which takes one argument. #!/usr/bin/tclsh

proc ftc {f} {

return

[expr $f * 9 / 5 + 32]

puts [ftc 100] puts [ftc 0] puts [ftc 30] We create a ftc procedure, which transforms fahrenheit temperature to celsius temperature. proc ftc {f} { The procedure takes one parameter. Its name f will be used in the body of the procedure. return [expr $f * 9 / 5 + 32] We compute the value of the celsius temperature. The return command returns the value to the caller. If the procedure doesn't execute an explicit return, then its return value is the value of the last command executed in the procedure's body. puts [ftc 100] The ftc procedure is executed. It takes 100 as a parameter. It is the temperature in fahrenheit. The returned value is used by the puts command, which prints it to the console. $ ./fahrenheit.tcl 212 32 86 Output.

Next we will have a procedure, which takes two arguments. #!/usr/bin/tclsh

proc maximum {x y} {
if {$x > $y}

return } else { return

$x

$y

set a 23 set b 32

set val [maximum $a $b] puts "The max of $a, $b is $val" We have a maximum procedure, which returns the maximum of two values. proc maximum {x y} { The method takes two arguments. if {$x > $y} {
return

$x

} else {
return

$y

} Here we compute which number is greater. set a 23 set b 32 We define two variables, which are to be compared. set val [maximum $a $b] We calculate the maximum of the two variables. $ ./maximum.tcl The max of 23, 32 is 32 Output. Variable number of arguments A procedure can take and process variable number of arguments. For this we use the special args argument.

#!/usr/bin/tclsh

proc sum {args} {

set s 0

foreach

arg $args {

incr s $arg }

return

$s

puts [sum 1 2 3 4] puts [sum 1 2] puts [sum 4] We define a sum procedure which adds up all its arguments. proc sum {args} { The sum procedure has a special args argument. It has a list of all values passed to the procedure. foreach arg $args {
incr s $arg

} We go through the list and calculate the sum. puts [sum 1 2 3 4] puts [sum 1 2] puts [sum 4] We call the sum procedure three times. In the first case, it takes 4 arguments, in the second case 2, in the last case one. We call the same method. $ ./variable.tcl

10 3 4 Output. Implicit arguments The arguments in Tcl procedures may have implicit values. An implicit value is used, if no explicit value is provided. #!/usr/bin/tclsh

proc power {a {b 2}} {

if {$b == 2} { return }

[expr $a * $a]

set value

for {set i 0} {$i<$b}

{incr i} {

set value }

[expr $value * $a]

return

$value

set v1 [power 5] set v2 [power 5 4]

puts "5^2 is $v1" puts "5^4 is $v2"

Here we create a power procedure. The procedure has one argument with an implicit value. We can call the procedure with one or two arguments. proc power {a {b 2}} { The second argument b, has an implicit value 2. If we provide only one argument, the power procedure then returns the value of a to the power 2. set v1 [power 5] set v2 [power 5 4] We call the power procedure with one and two arguments. The first line computes the value of 5 to the power 2. The second line value of 5 to the power 4. $ ./implicit.tcl 5^2 is 25 5^4 is 625 Output. Recursion Recursion, in mathematics and computer science, is a way of defining functions in which the function being defined is applied within its own definition. In other words, a recursive function calls itself to do its job. Recursion is a widely used approach to solve many programming tasks. Recursion calls have a limit in Tcl. There cannot be more than 1000 recursion calls. A typical example of recursion is calculation of the factorial. Factorial n!, is the product of all positive integers less than or equal to n. #!/usr/bin/tclsh

proc factorial n {

if {$n==0}

return } else {

return }

[expr $n * [factorial [expr $n - 1]]]

# Stack limit between 800 and 1000 levels

puts [factorial 4] puts [factorial 10] puts [factorial 18] In this code example, we calculate the factorial of three numbers. return [expr $n * [factorial [expr $n - 1]]] Inside the body of the factorial procedure, we call the factorial procedure with a modified argument. The procedure calls itself. $ ./recursion.tcl 24 3628800 6402373705728000 These are the results. If we tried to compute the factorial of 100, we would receive "too many nested evaluations" error. Scope A variable declared inside a procedure has a procedure scope. The scope of a name is the region of program text within which it is possible to refer to the entity declared by the name without qualification of the name. A variable which is declared inside a procedure has a procedure scope. It is also called a local scope. The variable is valid only in this particular procedure. #!/usr/bin/tclsh

proc test {} {

puts

"inside procedure" "x is $x"

#puts set x 4 puts

"x is $x"

set x 1

puts "outside procedure" puts "x is $x"

test

puts "outside procedure" puts "x is $x" In the preceding example, we have an x variable defined outside and inside of the test procedure. set x 4 puts "x is $x" Inside the test procedure, we define an x variable. The variable has local scope. It is valid only inside this procedure. set x 1 puts "outside procedure" puts "x is $x" We define an x variable outside the procedure. It has a global scope. The variables do not conflict, because they have different scopes. $ ./scope.tcl outside procedure x is 1 inside procedure x is 4 outside procedure x is 1 Output.

It is possible to change the global variable inside a procedure. #!/usr/bin/tclsh

proc test {} {

upvar x y puts puts set y puts

"inside procedure" "y is $y" 4 "y is $y"

set x 1

puts "outside procedure" puts "x is $x"

test

puts "outside procedure" puts "x is $x" We define a global x variable. We change the variable inside the test procedure. upvar x y We refer to the global x variable by the name y with the upvar command. set y 4 We assign a value to the local y variable and also change the value of the global x variable. $ ./scope2.tcl outside procedure x is 1 inside procedure y is 1 y is 4 outside procedure x is 4

From the output we can see, that the test procedure has changed the x variable.

With the global command, we can refer to global variables from procedures. #!/usr/bin/tclsh

proc test {} {

global x puts

"inside test procedure x is $x"

proc nested {} global x puts }

"inside nested x is $x"

set x 1

test nested

puts "outside x is $x" In the above example, we have a test procedure and a nested procedure defined within the test procedure. We refer to the global x variable from both procedures. global x puts "inside test procedure x is $x" With the global command, we refer to the global x variable, defined outside the test procedure. proc nested {} {
global x puts

"inside nested x is $x"

It is possible to create nested procedures. These are procedures defined inside other procedures. We refer to the global x variable with the global command. test nested We call the test procedure and its nested procedure. $ ./scope3.tcl inside test procedure x is 1 inside nested x is 1 outside x is 1 Output. In this part of the Tcl tutorial, we covered Tcl procedures.

11.Input & output In this chapter, we will work with input, output operations in Tcl. Tcl has several commands for doing io. We will cover a few of them.

Tcl uses objects called channels to read and write data. The channels can be created using the open or socket command. There are three standard channels, which are available to Tcl scripts without explicitly creating them. They are automatically opened by the OS for each new application. They are stdin, stdout and stderr. The standard input,stdin, is used by the scripts to read data. The standard output, stdout, is used by scripts to write data. The standard error stderr is used by scripts to write error messages. In the first example, we will work with the puts command. It has the following synopsis: puts ?-nonewline? ?channelId? string The channelId is the channel, where we want to write text. The channelId is optional. If not specified, the default stdout is assumed. $ cat print.tcl #!/usr/bin/tclsh

puts "Message 1" puts stdout "Message 2" puts stderr "Message 3"

The puts command writes text to the channel. puts "Message 1" If we do not specify the channelId, we write to stdout by default. puts stdout "Message 2" This line does the same thing as the previous one. We only have explicitly specified the channelId. puts stderr "Message 3" We write to the standard error channel. The error messages go to the terminal by default. $ ./print.tcl Message 1 Message 2 Message 3 Output.

In the next example, we will be reading from the standard input channel. #!/usr/bin/tclsh

puts -nonewline "Enter your name: " flush stdout set name [gets stdin]

puts "Hello $name" The script asks for input from the user and then prints a message. puts -nonewline "Enter your name: " The puts command is used to print messages to the terminal. But the command can write to any channel, not just terminal. flush stdout Tcl buffers output internally, so characters written with puts may not appear immediately on the output file or device. We can force output to appear immediately with the flush command. set name [gets stdin]

The gets command reads a line from a channel. $ ./hello.tcl Enter your name: Jan Hello Jan Sample output of the script.

The read command is used to read data from the channel. #!/usr/bin/tclsh

set c [read stdin 1]

while {$c != "q"} {

puts

-nonewline "$c"

set c [read stdin 1]

} The script reads a character from the standard input channel and then writes it to the standard output until it encounters a q character. set c [read stdin 1] We read one character from the standard input channel (stdin). while {$c != "q"} { We continue reading characters until the q is pressed.

Tcl has pwd and cd commands, similar to shell commands. The pwd command returns the current working directory and the cd command is used to change the working directory. #!/usr/bin/tclsh

set dir [pwd]

puts $dir

cd ..

set dir [pwd] puts $dir In this script, we will print the current working directory. We change the working directory and print the working directory again. set dir [pwd] The pwd command returns the current working directory. cd .. We change the working directory to the parent of the current directory. We use the cdcommand. $ ./cwd.tcl /home/vronskij/programming/tcl/io /home/vronskij/programming/tcl Output.

Tcl has a glob command, which returns the names of the files that match a pattern. #!/usr/bin/tclsh

set files [glob *.tcl]

foreach file $files {

puts

$file

} The script prints all files with .tcl extension to the console. set files [glob *.tcl] The glob command returns a list of files that match the *.tcl pattern. foreach file $files {

puts

$file

} We go through the list of files and print each item of the list to the console. $ ./glob.tcl isfile.tcl readfile.tcl attributes.tcl allfiles.tcl cwd.tcl addnumbers.tcl glob.tcl write2file.tcl files.tcl An example from a certain directory.

In the following code example, we are going to check if a file name is a regular file or a directory. #!/usr/bin/tclsh

set files [glob *]

foreach fl $files {

if {[file isfile $fl]} puts } elseif { puts }

"$fl is a file"

[file isdirectory $fl]} {

"$fl is a directory"

} We go through all file names in the current working directory and print whether it is a file or a directory. set files [glob *]

Using the glob command we create a list of file and directory names of a current directory. if {[file isfile $fl]} { We execute the body of the if command, if the file name in question is a file. } elseif { [file isdirectory $fl]} { The file isdirectory command determines, whether a file name is a directory. Note that on Unix, a directory is a special case of a file.

Next, we are going to write to a file. #!/usr/bin/tclsh

set fp [open days w]

set days {Monday Tuesday Wednesday Thursday Friday Saturday Sunday}

puts $fp $days close $fp In the script, we open a file for writing. We write days of a week to a file. set fp [open days w] We open a file named "days" for writing. The open command returns a channel id. set days {Monday Tuesday Wednesday Thursday Friday Saturday Sunday} This data is going to be written to the file. puts $fp $days We used the channel id returned by the open command to write to the file. close $fp We close the opened channel. $ ./write2file.tcl $ cat days Monday Tuesday Wednesday Thursday Friday Saturday Sunday

We run the script and check the contents of the days file.

In the following script, we are going to read data from a file. $ cat languages Python Tcl Visual Basic Perl Java C C# Ruby Scheme We have a simple file called languages in a directory. #!/usr/bin/tclsh

set fp [open languages r] set data [read $fp]

puts -nonewline $data

close $fp set fp [open languages r] We create a channel by opening the languages file in a read-only mode. set data [read $fp] If we do not provide a second parameter to the read command, it reads all data from the file until the end of the file. puts -nonewline $data We print the data to the console. $ ./readfile.tcl Python Tcl

Visual Basic Perl Java C C# Ruby Scheme Sample run of the readfile.tcl command.

The next script performs some additional file operations. #!/usr/bin/tclsh

set fp [open newfile w]

puts $fp "this is new file" flush $fp

file copy newfile newfile2 file delete newfile

close $fp We open a file and write some text to it. The file is copied. The original file is then deleted. file copy newfile newfile2 The file copy command copies a file. file delete newfile The original file is deleted with the file delete command.

In the final example, we will work with file attributes. #!/usr/bin/tclsh

set files [glob *]

set mx 0

foreach fl $files {
set len

[string length $fl]

if {

$len > $mx} {

set mx $len }

set fstr "%-$mx\s %-s" puts [format $fstr Name Size]

set fstr "%-$mx\s %d bytes" foreach fl $files {

set size [file size $fl]

puts

[format $fstr $fl $size]

} The script creates two columns. In the first column, we have the name of the file. In the second column, we display the size of the file. foreach fl $files {
set len

[string length $fl]

if {

$len > $mx} {

set mx $len }

} In this loop, we find out the most lengthy file name. This will be used when formatting the output columns. set fstr "%-$mx\s %-s" puts [format $fstr Name Size] Here we print the headers of the columns. To format the data, we use the formatcommand. set fstr "%-$mx\s %d bytes" foreach fl $files {
set size [file size $fl]

puts

[format $fstr $fl $size]

} We go through the list of files and print each file name and its size. The file size command determines the size of the file. $ ./attributes.tcl Name isfile.tcl tmp Size 219 bytes 4096 bytes

readfile.tcl 98 bytes attributes.tcl 337 bytes allfiles.tcl 75 bytes read.tcl~ cwd.tcl 114 bytes 76 bytes

Sample run. In this chapter, we have covered Input/Output operations in Tcl.

Vous aimerez peut-être aussi