I am very new for TCL. Just I want to know that how to write TCL procedures without argument and how to call and how to execute it.
To write a procedure that doesn't take any arguments, do this:
proc someName {} {
# The {} above means a list of zero formal arguments
puts "Hello from inside someName"
}
To call that procedure, just write its name:
someName
If it was returning a value:
proc example2 {} {
return "some arbitrary value"
}
Then you'd do something with that returned value by enclosing the call in square brackets and using that where you want the value used:
set someVariable [example2]
To execute it... depends what you mean. I assume you mean doing so from outside a Tcl program. That's done by making the whole script (e.g., theScript.tcl) define the procedure and do the call, like this:
proc example3 {} {
return "The quick brown fox"
}
puts [example3]
That would then be run something like this:
tclsh8.5 theScript.tcl
You can define a procedure like this:
proc hello_world_proc {} {
puts "Hello world"
}
And you can execute it by simply writing:
hello_world_proc
If you want to use a return value of the procedure, you can do:
# Procedure declaration
proc hello_world_proc2 {} {
return "Hello world"
}
# Procedure call
puts [hello_world_proc2]
proc myProc {} {
# do something
}
# call proc
myProc
Te official Tcl website has some documentation on functions (procedures) that could help you at https://www.tcl.tk/man/tcl/TclCmd/proc.htm.
Procedure with no argument
If you don't need any argument here is how to write the procedure you want:
proc funcNameNoArgs {} {
puts "Hello from funcNameNoArgs"
}
And you can call it as follows:
funcNameNoArgs
Procedure with arguments
Now let's say you need arguments in the future. Here is the way to write that precedure in TCL:
proc funcNameWithArgs {arg1 arg2 arg3} {
puts "Hello from funcNameWithArgs "
}
You can call that function by doing:
funcName arg1 arg2 arg3
Here is a piece of code for you to try!
Remember to define functions before you call them, or you will get an error.
Try to copy paste this code in your interpreter to get started and play with it:
proc funcNameNoArgs {} {
puts "Hello from a function with no arguments"
}
funcNameNoArgs
proc funcNameWithArgs {arg1 arg2 arg3} {
puts "Hello from a function with 3 arguments"
puts $arg1
puts $arg2
puts $arg3
}
funcNameWithArgs "Argument 1" "Argument 2" "Argument 3"
Syntax of procedure
proc <Name Of procedure> {No of arguments, if u want don't need simply left empty} {
<Body>
}
Let See the Example:
Without Arguments:
proc Hello_eg { } { puts "Hello I M In procedure" }
How to run:
step 1: write tclsh on prompt
step 2: write the procedure as per above mention
step 3: write just the procedure name (i.e Hello_eg) to run the procedure
2.With Arguments:
proc Hello_Arg { first second }
{
puts "The first argument is: $first"
puts "The Second argument is: $second"
}
How to run this:
step 1: write tclsh on prompt
step 2: write the procedure as per above mention
step 3: write just the procedure name with arguments (i.e Hello_Arg Ramakant Singla) to run the procedure
It's pretty simple.
Defining :
proc myproc {} {
}
calling :
myproc
Since you are New, I advise you to go through tutorial point. They have simple and consolidated content.
Procedure is a set of statements which is being preapeated in a program.
Syntax
proc <Name> {INPUTS} {
BODY
}
Eg:
proc add {m n} {
set s 0
set s [expr $m + $n]
return $s
}
#Main Program Starts Here
set x 2
set y 3
set Result [add $x $y]
puts "$Result"
In the above example....in procedure we have provide a name (add) to the set of statements which can be call in the main program.
Any amount of arguments
What maybe would come in handy is using args.
By using args you can pass any amount of arguments to your procedure.
proc withAnyNumberOfArguments {args} {
if {$args eq ""} {
puts "got no arguments"
}
foreach arg $args {
puts "got $arg"
}
}
Optional Arguments
Another tip: Enclosing arguments with { } makes them optional arguments.
proc atLeastOneArgument {a1 {args}} {
puts -nonewline "got a1=$a1"
foreach arg $args {
puts -nonewline " and $arg"
}
puts "."
}
Default Values
If you want to have default values you can specify them as follows:
proc putsTime { {secondsSinceBeginOfEpoch "now"} } {
if {$secondsSinceBeginOfEpoch eq "now"} {
set secondsSinceBeginOfEpoch [clock seconds]
}
return [clock format $secondsSinceBeginOfEpoch]
}
Some Example Calls
1 % withAnyNumberOfArguments
got no arguments
2 % withAnyNumberOfArguments one
got one
3 % withAnyNumberOfArguments ready steady go!
got ready
got steady
got go!
4 % atLeastOneArgument "this is one argument" ;# because its in double quotes
got a1=this is one argument.
5 % atLeastOneArgument 3 2 1 go!
got a1=3 and 2 and 1 and go!.
6 % puts [formatTime]
Fri Dec 18 16:39:43 CET 2015
7 % puts [formatTime 0]
Thu Jan 01 01:00:00 CET 1970
In addition to the answers above, I would recommend using tcltutor.exe (available from http://tcltutor.software.informer.com/3.0b/) to learn TCL.
It'll have a chapter on Subroutines that'll help you define a TCL proc without and with arguments.
Regards
Sharad
To create a TCL procedure without any parameter you should use the proc keyword followed by the procedure name then the scope of your procedure.
proc hello_world {} {
// Use puts to print your output in the terminal.
// If your procedure return data use return keyword.
}
You can use the created procedure by simply calling its name:
hello_world
This solution is based on previous questions about writing procs. I personally feel this is one of the better ways to write a procedure in tcl.
Code
proc sampleProc args {
# Defaults
array set options {-device router0 -ip "10.16.1.62"}
# Read args
array set options $args
# Assign
set device $options(-device)
set ip $options(-ip)
# Usage
puts "Device under use is $device and IP is $ip"
# Return
return "${sd} :: $ip"
}
Execution
tclsh> source sampleProc.tcl
Device under use is router0 and IP is 10.16.1.62
router0 :: 10.16.1.62
Related
I have a "library" type file that where I define a namespace and export some functions to "print" debug info or "trace" info in TCL.
proc cputs { args } {
puts "Test= $args"
}
I import this function in multiple other files. When I use it everything is fine except it add bracket to the output.
Like if I call cputs "Hi there" it will output {Hi there} instead of Hi there.
Can't find anything to explain that. I would like to get ride of those brackets.
Any help would be appreciated.
Thanks
If you do not want to pass an arbitrary, unknown numbers of arguments to your cproc, do not use args (which has a special meaning as a parameter name), but msg, for instance.
proc cputs {msg} {
puts "Test= $msg"
}
See also proc documentation:
If the last formal argument has the name “args”, then a call to the
procedure may contain more actual arguments than the procedure has
formal arguments. In this case, all of the actual arguments starting
at the one that would be assigned to args are combined into a list (as
if the list command had been used); this combined value is assigned to
the local variable args.
If you want to take an arbitrary number of arguments (since args is a special name), you should join or concat things before printing. These two options differ in their treatment of extra whitespace; use the one that suits you.
proc cputs { args } {
puts "Test= [join $args]"
}
cputs "Hello there " " from an example"
# Test= Hello there from an example
proc cputs { args } {
puts "Test= [concat {*}$args]"
}
cputs "Hello there " " from an example"
# Test= Hello there from an example
Is it possible to find the procedure name by using the content of that procedure?
For example,
proc test {args} {
set varA "exam"
puts "test program"
}
Using the statement set varA, is it possible to find its procedure name test?
Because, I need to find a procedure for which i know the output [it's printing something, i need to find the procedure using that].
I tried many ways like info frame, command. But, nothing helps.
Is it possible to find the procedure name by using the content of that procedure?
Yes. You use info level 0 to get the argument words to the current procedure (or info level -1 to get its caller's argument words). The first word is the command name, as resolved in the caller's context. That might be enough, but if not, you can use namespace which inside an uplevel 1 to get the fully-qualified name.
proc foo {args} {
set name [lindex [info level 0] 0]
set FQname [uplevel 1 [list namespace which $name]]
# ...
}
Note that this does not give you the main name in all circumstances. If you're using aliases or imported commands, the name you'll get will vary. Mostly that doesn't matter too much.
With info proc, we can get the content of a procedure which may helps you in what you expect.
The following procedure will search for the given word in all the namespaces. You can change it to search in particular namespace as well. Also, the search word can also be case insensitive if altered in terms of regexp with -nocase. It will return the list of procedure names which contains the search word.
proc getProcNameByContent {searchWord} {
set resultProcList {}
set nslist [namespace children ::]; # Getting all Namespaces list
lappend nslist ::; # Adding 'global scope namespace as well
foreach ns $nslist {
if {$ns eq "::"} {
set currentScopeProcs [info proc $ns*]
} else {
set currentScopeProcs [info proc ${ns}::*]
}
foreach myProc $currentScopeProcs {
if {[regexp $searchWord [info body $myProc]]} {
puts "found in $myProc"
lappend resultProcList $myProc
}
}
}
return $resultProcList
}
Example
% proc x {} {
puts hai
}
% proc y {} {
puts hello
}
% proc z {} {
puts world
}
% namespace eval dinesh {
proc test {} {
puts "world is amazing"
}
}
%
% getProcNameByContent world
found in ::dinesh::test
found in ::z
::dinesh::test ::z
%
i want to use the variable assigned outside (proc) to be used inside the proc . For example i tried the following thing
set a 10
proc myproc { } {
puts $a
}
myproc
I am expecting the above script to print 10 . But the above script is erroring out "can't read "a": no such variable"
I cannot pass $a as argument to script because i have lot such variables i want to use inside my proc inside my script . Could you please help me to solve this problem ?
Your help is appreciated
If the variable is declared at the same stack level as the call to myproc then you can do following in your proc:
upvar a a
like this:
set a 10
proc myproc { } {
upvar a a
puts $a
}
myproc
and then you can use $a locally in the procedure. The upvar command "links" a variable declared somewhere in the stack with a local variable. If the variable is declared more than 1 level deeper in the stack, thn you need to pass "2" to upvar, so it knows where to look for the variable:
upvar 2 a a
If you don't pass the "2" (or other value), the upvar assumes default lookup depth of 1.
You can read more details about upvar in Tcl documentation for that command.
If the variable a is always a global variable (declared at the script top level), then you can use:
global a
in your procedure, instead of upvar.
If you have namespaces you could always assign it there :
namespace eval blah {
variable a 10
}
proc blah::myproc { } {
variable a
puts $a
}
blah::myproc
This way you can avoid potential collisions with other global variables
I am trying to create a trace function in tcl .Function will list down all the called procs/nested calls and there arguments. Below is the script
rename proc _proc
proc proc {nm params body} {
_proc $nm $params $body
trace add execution $nm enter [list track_entry $nm $params]
trace add execution $nm leave [list track_leave $nm]
}
_proc track_entry {nm params real args} {
puts "Enter proc $nm"
foreach formal $params actual [lrange $real 1 end] {
append p " [lindex $formal 0]=$actual,"
}
puts "Parameters:$p and body"
}
_proc track_leave {nm args} {
puts "Exit proc $nm"
}
proc test1 { param1 param2 } {
puts “parameters are $param1 and $param2”
test2 value1
}
proc test2 { value} {
puts “value is $value”
}
I am getting below output
test1 arg1 arg2
Enter proc test1
Parameters: param1=arg1, param2=arg2, and body
Exit proc test1
wrong # args: should be "puts ?-nonewline? ?channelId? string"
Any clue why it is giving error in puts
Provided that what you posted is correct, the problem is you're not using the correct quoting character.
Tcl only understands two kinds of quoting:
quoting with substitutions: ""
quoting without substitutions: {}
The character “ in tcl will just be treated as any other character such as a or 5.
Note that without quoting, tcl treats the word as a string without spaces. For example, the following examples are all valid strings:
this_is_a_valid_string
"this_is_a_valid_string"
{this_is_a_valid_string}
Following this simple rule, the following are also valid strings and are all equivalent:
“hello
"“hello"
{“hello}
So when you ask tcl to execute the following:
puts “parameters are $param1 and $param2”
it treats it as:
puts {“parameters} {are} "$param1" {and} "$param2”"
passing 5 arguments to puts.
Obviously this would trigger an error since puts expects either one or two arguments.
How to know what is the name of the proc in which I am. I mean I need this:
proc nameOfTheProc {} {
#a lot of code here
puts "ERROR: You are using 'nameOfTheProc' proc wrongly"
}
so I want to obtain "nameOfTheProc" but not hard-code. So that when someone will change the proc name it will still work properly.
You can use the info level command for your issue:
proc nameOfTheProc {} {
#a lot of code here
puts "ERROR: You are using '[lindex [info level 0] 0]' proc wrongly"
puts "INFO: You specified the arguments: '[lrange [info level [info level]] 1 end]'"
}
With the inner info level you will get the level of the procedure call depth you are currently in. The outer one will return the name of the procedure itself.
The correct idiomatic way to achieve what's implied in your question is to use return -code error $message like this:
proc nameOfTheProc {} {
#a lot of code here
return -code error "Wrong sequence of blorbs passed"
}
This way your procedure will behave exactly in a way stock Tcl commands do when they're not satisfied with what they've been called with: it would cause an error at the call site.
If your running Tcl 8.5 or later the info frame command will return a dict rather than a list. So modify the code as follows:
proc nameOfTheProc {} {
puts "This is [dict get [info frame [info frame]] proc]"
}