TCL Usage Overview


TCL (pronounced "tickle") is a simple and powerful scripting language that lets you program functions in the CLI of the Sun Secure Application Switch. The CLI includes a TCL interpreter and supports TCL Version 8.3.3. TCL commands are fully integrated with the CLI, so that you do not have to change environments or shells. The CLI includes only basic TCL built-in commands and it does not include TK (GUI Toolkit), Safe TCL, other TCL extensions, or command reference documentation (man pages).

TCL references

This document does not explain how to use TCL or describe the syntax for the supported TCL commands. If you are unfamiliar with using TCL, refer to http://www.tcl.tk.

TCL commands

The following table lists the TCL commands that the CLI supports.

Command Description
append Append to a variable.
array Manipulate array variables.
auto_import Determine whether specified imported commands reside in an autoloaded library and load the commands.
auto_load Attempt to load the definition for a command.
auto_qualify Compute a list of fully qualified names for a command.
binary Insert and extract fields from binary strings.
break Abort a looping command.
case Evaluate one of several scripts, depending on a pattern match. (This command is deprecated. Use the switch command instead.)
catch Evaluate a TCL script and trap exceptional returns.
cd Change working directory.
close Close an open channel.
concat Join (concatenate) lists.
continue Skip to the next iteration of a loop.
cp Copy a file to a specified destination.
eof Check for end-of-file condition on a channel.
error Generate an error and display a message.
eval Evaluate a TCL script.
expr Evaluate an expression.
fblocked Determine whether the last input operation exhausted all available input.
fconfigure Set and retrieve options on a channel.
fcopy Copy data from one channel to another.
file Manipulate a file and its attributes.
for Execute a loop.
foreach Iterate over all elements in one or more lists.
format Format a string in the same way as the ANSI C sprintf command.
gets Read the next line from a channel.
glob Return names of files that match patterns.
global Access global variables instead of local variables.
if Execute a TCL script conditionally.
incr Increment the value of an integer variable.
info Return information about the state of the TCL interpreter (for example, variables and procedures).
join Create a string by joining the elements of a list.
lappend Append elements of a list to a variable.
lindex Retrieve an element from a list.
linsert Insert elements into a list.
list Create a list.
llength Count the number of elements in a list.
lrange Return a new list containing sequential elements from an existing list.
lreplace Return a new list formed by replacing elements of a list with new elements.
ls List the contents of a directory. A Sun addition.
lsearch Determine whether a list contains a particular element.
lsort Sort the elements of a list and return a new list in sorted order.
mkdir Create a directory.
mv Move a file to a specified destination.
namespace Create and manipulate contexts for commands and variables.
open Open a file, serial port, or command pipeline and return a channel identifier.
package Manipulate a database of packages available for use by the current TCL interpreter.
pause Pause a TCL script for a specified number of seconds.
pid Retrieve process id(s).
proc Create a TCL procedure.
puts Write characters to a channel.
pwd Return the path name of the current working directory.
read Read characters from a channel.
regexp Determine whether a regular expression matches a string.
regsub Substitute strings in variables using regular expression pattern matching.
rename Rename or delete a TCL command.
return Return from the current procedure.
rm Removes a file or directory.
scan Parse a string using conversion specifiers in the same way as the ANSI C sscanf command.
seek Change the current access position for an open channel.
set Create, read, or write a variable.
source Pass a file to the TCL interpreter as a text script.
split Split a string into a proper TCL list.
string Manipulate a string in various ways, for example, compare, search, and character type.
subst Substitute variables, commands, and backslashes in a string.
switch Evaluate one of several scripts, depending on a pattern match.
tell Return the current access position in an open channel.
tclflush Flush any output that has been buffered for a channel.
trace Execute a TCL command whenever a given variable is accessed.
unknown Handle attempts to invoke non-existent TCL commands.
unset Delete one or more variables.
uplevel Execute a script in a different level of the procedure calling stack.
upvar Create a link to a variable in a different level of the procedure calling stack.
variable Create and initialize a namespace variable.
while Execute a script repeatedly as long as a Boolean condition is true.

TCL use guidelines

Consider the following guidelines when you use TCL:

sun> expr Enter
wrong # args: should be "expr arg ?arg ...?"

Using numbers

TCL commands accept both decimal and hexadecimal numbers, and return decimal numbers. For example:

sun> set num 0xf 0xf sun> incr num 16 sun> puts $num 16 sun> expr pow($num,4) 65536.0 sun> expr 0xa * 10 100

Using the ls command

The ls command lists the contents of a directory.

Syntax

ls [-a] [-l] [name ...]

Arguments

Argument Description
-a
List all files, including hidden files beginning with a period (.).
-l
List contents in long format, which includes directory designator, user/group/other permissions (read, write, execute), size in bytes, date and time last modified, and name. Subdirectory names end with a slash (/).
name ...
Display information about the named files or directories. You must enter the full file or directory name(s). Wildcards are not allowed.
Without this argument, the ls command lists the contents of the current directory.

Examples

In this example, the ls command, without any arguments, shows a listing of the current directory.

sun> ls Directory '/ftl0/' nosConfig errhnd evtMgr.elf.stub halagent.elf.stub logMgr.elf.stub ui.elf.stub lib/ cdb.bak cdb.dat

In this example, the ls -l command shows a detailed listing of the files in the current directory.

sun> ls -l Directory '/ftl0/' -rw-rw-rw- 180 1 Jan 2002 00:10:35 nosConfig -rw-rw-rw- 9999 14 Jan 2002 16:48:45 errhnd -rw-rw-rw- 4616 14 Jan 2002 16:50:06 evtMgr.elf.stub -rw-rw-rw- 4616 14 Jan 2002 16:50:08 halagent.elf.stub -rw-rw-rw- 4616 14 Jan 2002 16:50:10 logMgr.elf.stub -rw-rw-rw- 4616 14 Jan 2002 16:50:44 ui.elf.stub drwxrwxrwx 512 1 Jan 2002 00:04:12 lib/ -rw-rw-rw- 649 9 Jan 2002 19:08:55 cdb.bak -rw-rw-rw- 685 14 Jan 2002 16:51:25 cdb.dat sun>

In this example, the ls -l command with a file name shows a detailed listing for the specified file.

sun> ls -l cdb.dat -rw-rw-rw- 685 14 Jan 2002 16:51:25 cdb.dat

Using the pause command

The pause command lets you pause a TCL script or the CLI. This command is a Sun addition.

Syntax

pause seconds

Argument

Argument Description
seconds
The number of seconds to pause. The valid range is 0 through 4294967295.

Example

In this example, the pause command inserts a 30-second pause in the script.

sun# proc test args { vSwitch create pause 30 puts "vSwitch is fully up and working." }

TCL examples

This section contains simple examples of using TCL with the CLI to quickly complete configuration tasks.

Configuring multiple vSwitches with a script

sun(config)# foreach i {eng pubs fin} {vSwitch $i; exit; }; create new vSwitch "eng" ? (y or n): y ......................................... create new vSwitch "pubs" ? (y or n): y ......................................... create new vSwitch "fin" ? (y or n): y ......................................... sun(config)# show vSwitch Name: eng ID: 2 Description: N/A Admin State: enabled Operational Status: up Name: fin ID: 4 Description: N/A Admin State: enabled Operational Status: up Name: pubs ID: 3 Description: N/A Admin State: enabled Operational Status: up Name: system ID: 0 Description: System vSwitch Admin State: enabled Operational Status: up

Creating variables for CLI commands

This example shows how to use TCL to create a variable that you can use in CLI commands. The variable in this example represents an IP address for an NTP server. You can use the variable in CLI commands instead of entering the server's IP address.

Note:Variables persist only for the duration of the current CLI session. If you restart the CLI, you must re-create any TCL variables.
sun(switchServices)# set ip 172.26.3.10 172.26.3.10 sun(switchServices)# ntp primary $ip minpoll 256 maxpoll 2048 sun(switchServices)# show ntp * $ip Server type: Primary Server IP Address: 172.26.3.10 Server Preference: N/A Burst Mode: N/A Min. Poll Interval: 256 Max. Poll Interval: 2048 Version: N/A sun# event sun(event)# syslog $ip loglevel warning sun(event)# show syslog $ip SysLog Syslog Log Host Port Level 172.26.3.10 N/A warning

TCL error messages

The TCL interpreter displays descriptive error messages if you enter invalid commands or keywords, or if an operation fails. The following table lists the common error messages.

Command and error
Description and solution
sun# append [Enter] wrong # args: should be "append varName ?value value ...?"
The command is incomplete, and the error message displays the correct syntax. Enter the command with its required arguments.
sun# ntp sec $pi can't read "pi": no such variable
The variable does not exist. Create a variable before you use it. Variables persist only for the duration of the current CLI session. If you restart the CLI, you must re-create any TCL variables. Use the TCL info vars command to display current variables. Variables are case-sensitive. Correct any typing errors.
sun# ls -l foo.txt Could not stat 'foo.txt': No such file or directory.
The file does not exist in the current directory. This result is not necessarily an error; the file may be in a different directory. Check the file name and correct any typing errors.
sun# Expr 64 ^ 8 ERROR: "Expr" is not a recognized command
TCL commands are case-sensitive and are lowercase. Enter the command in all lowercase characters.
sun# set pi 3.14159 3.14159 sun# incr pi expected integer but got "3.14159"
You can increment only integer variables. Use expr to add to a real variable, or change the variable to an integer.
sun# expr pi * 5 syntax error in expression "pi * 5"
Prefix a variable with $ to substitute its value in a command. In this example, use $pi.

TCL and scripted server health checks

Using TCL scripts in conjunction with the SCRIPT health check probe type enables you to write customized server health checks to verify real service availability. Executed within the virtual switch that is running the server health check, the script can range from simple TCL commands to complicated protocol-specific server health checks. Sharing many of the same arguments that define the other types of health checks, scripted health checks also have specific parameters such as scriptFile, scriptCommands, and scriptArgs.

The most significant difference between scripted health checks and the other types of health checks is the higher volume of system resources required by scripted health checks. Rather than performing the protocol-level exchange directly from a single application like the other health check types, the scripted health check process creates a task to run a new, freshly initiated TCL interpreter each time a script is executed. Although a new, separate interpreter ensures the same predictable starting point for each server probe, this task places a great demand on system resources.

The execution of a scripted health check begins with the evaluation of the TCL scriptFile (when specified). Although the script file can contain TCL commands, it is recommended that the file contain TCL procedures. These procedures can then be launched by the scriptCommands argument. This is an easier way of writing scripts and provides an additional method for passing arguments.

If no errors are detected during the evaluation, the script commands, which can be simple TCL commands or process execution statements, are executed. During command execution, TCL errors, indicating a failure, are reported. To ensure that a success status is reported if there are no TCL errors, you can use script logic to set a particular error code as an "exit code." An exit code of 0 indicates success; a non-zero exit code indicates failure. If an exit code is not set, and no TCL errors are reported, successful execution is assumed.

The following topics describe:

An example is also provided to show how to use TCL scripts with scripted server health checks.

TCL global variables

Real service target information is passed by the following global variables used within a defined TCL procedure.

Optional global arguments may be available, depending on the configuration of the scripted health check profile.

Health check profile arguments

The following are optional arguments for the SCRIPT health check profile. You set the values using the healthCheckProfile command.

The following are the arguments that are shared by all health check probe types.

TCL and scripted server health check example

The following example shows a test script file for use in scripted server health checks. Comments (#) are included in the file to describe the variables and arguments that are available.

# -------------------------------------------------------------------------------------------------------------------------------------------------------------------------
# Description: this is a test script file that demonstrates some of the scripted health check capabilities.
# The script opens a socket to a target, and sends an http request. Note that the target url does not
# have to be valid. Completion of opening and sending the request indicates that the server is at
# least available.
#
# The TCL test script (shc_script.tcl) uses the following arguments:
#
# probeLevel - defines the depth (0 to 5 and above) of the probe for performing a full http get of the root file.
#
# debugMode - defines whether the proc will log output to a file. Since this operation is quite slow, the debug
# mode should be used only to verify script operation. The debugMode argument should not normally be enabled
#
# Additionally, the proper response can be retrieved and verified, or simply ignored.
#
# This example uses the following displayed health check profile (hc1) and the test script file shc_script.tcl,
# both of which reside in flash memory in directory /ftl0.
#
# sun(config-vSwitch-vsw1 loadBalance)# show healthCheckProfile
# Name: hc1
# Type: SCRIPT
# Interval: 5
# Retries: 3
# Success Rate: 0
# Timeout: 2
# Count: 3
# Script File: /ftl0/shc_script.tcl
# **Script Commands: shc-script-http 5
# Script Arg1: value_for_arg1
# Script Arg2: value_for_arg2
# Script Arg3: value_for_arg3
# Script Arg4: value_for_arg4
#
# ** The specified Script Commands indicates that this procedure is called in `quiet' mode with debugMode
# OFF(0) by default. If debugMode were enabled, individual host/port files would be written to the file
# system. To enable debugMode, set the value to ON(1) as the second calling argument as shown below.
#
# Script Commands: shc-script-http 5 1
#
# With debugMode set to 1, individual real service activity is logged in a file, shc_<ipAddress>p<port>.txt.
#
# If the hostIp value is 192.168.124.238, port 80, the output file would be named:
#
# shc_192.168.124.238p80.txt
# -------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#
proc shc-script-http { { probeLevel 0 } { debugMode 0 } } { # In the TCL proc, real service target information is passed using the # following global variables. global shc_real_service_ip global shc_real_service_port # # The following optional arguments may be used, depending on the # configuration of the SHC Profile for the scripted health check. # global shc_arg1 global shc_arg2 global shc_arg3 global shc_arg4 # The global variable shc_state_info stores script state, # which can be used to pass state information regarding the last # execution of the script. The variable can contain string data # between 0-32 chars in length. This value will be available for # the next probe's script exection. The script state can include # information such as the status of the previous run, an # incrementing counter, a history summary, or average successes. It # can be a single value, a list of values, or just a summary. # global shc_state_info # The global variable 'shc_exit_code' can be used to indicate script # execution success or failure. If it is not set, and there are no # other TCL errors, success is assumed. The possible values of the # shc_exit_code are 0 = success, non-zero = error. # global shc_exit_code # Initialize the returned error first, and clear it upon success. # set shc_exit_code 10 # Open a file to catch the output and dump the internal # variables that are available to the script. # # set dyn_output_file "/ftl0shc_$shc_real_service_ip_ # $shc_real_service_port.txt" # if { $debugMode != 0 } { set dyn_output_file "/ftl0/shc_" append dyn_output_file "$shc_real_service_ip" append dyn_output_file "p" append dyn_output_file "$shc_real_service_port" append dyn_output_file ".txt" set outputName "$dyn_output_file" # Open the file and rewrite it each time (w+) rather than appending # to it (a+) since appending will cause the file to grow rapidly. set gotError [ catch { set fname [ open "$outputName" w+ ] } ] catch { puts $fname " shc-script-http... " } catch { puts $fname " " } catch { puts $fname " Dynamic FileName: $dyn_output_file " } catch { puts $fname " calling arg : $calling_arg " } catch { puts $fname " RS IP Address: $shc_real_service_ip " } catch { puts $fname " RS Port Num: $shc_real_service_port" } catch { puts $fname " " } catch { puts $fname " State_Info: $shc_state_info " } catch { puts $fname " arg_1: $shc_arg1 " } catch { puts $fname " arg_2: $shc_arg2 " } catch { puts $fname " arg_3: $shc_arg3 " } catch { puts $fname " arg_4: $shc_arg4 " } catch { puts $fname " " } catch { puts $fname " " } } # Initialize the errors to zero # set sockError 0 set fconError 0 set putsError 0 set recvError 0 set rsSock "not-set" set stagesSet "" set inLIne "" if { $probeLevel > 1 } { append stagesSet "socket" set sockError [ catch { set rsSock [ socket $shc_real_service_ip $shc_real_service_port ] } ] } else { set rsSock "not-set and not-required" } if { $probeLevel > 2 } { append stagesSet " fconfig" set fconError [ catch { fconfigure $rsSock -buffering none -eofchar {} } ] }
if { $probeLevel > 3 } { append stagesSet " get" set putsError [ catch { puts -nonewline $rsSock "GET / HTTP/1.0\n\n" } ] }
if { $probeLevel > 4 } { append stagesSet " receive" set recvError [ catch { set inLine [ read $rsSock ] } ] } # Clean up the socket, if it was opened # if { $rsSock != "not-set" } { append stagesSet " closed-socket" catch { close $rsSock } } # Gather updated info about the current probe count, which will be used # to provide additional state information about the probe success or # failure. It will also provide a probe 'count' value in case it # is needed. # set l_len 0 catch { set l_len [ llength $shc_state_info ] } if { $l_len >= 5 } { set prev_probe [ lindex $shc_state_info 4 ] } else { set prev_probe 0 }
set probeCount [ expr $prev_probe + 1 ] # Summarize the errors, and set the appropriate return code and state info. # if { $sockError == 0 && $fconError == 0 && $putsError == 0 && $recvError == 0 }{ set shc_exit_code 0 set shc_state_info "prev probe was OK $probeCount" } else { set shc_exit_code 1 set shc_state_info "prev probe was NotOK $probeCount" } if { $debugMode != 0 } { catch { puts $fname " rsSock: $rsSock " } catch { puts $fname " inLine: $inLine " } catch { puts $fname " stages: $stagesSet " } catch { puts $fname " " } catch { puts $fname " exit code: $shc_exit_code " } catch { puts $fname " " } if { $shc_exit_code == 0 } { catch { puts $fname " Success! sock: $sockError, fconf: $fconError" } catch { puts $fname " puts: $putsError, recv: $recvError" } } else { catch { puts $fname " ERROR! sock: $sockError, fconf: $fconError" } catch { puts $fname " puts: $putsError, recv: $recvError" } } catch { close $fname } } } # proc shc-script-http