Getting Logs of Console in Variable in TCL - bash

Is it possible to get logs generated by one function in variable without returning that value from that function in TCL like what "$" used to be do in BASH.
function f1 {
echo "ABC"
return 0
}
Calling procedure is,
var=$(f1) ;# gives output ABC
What i know about how to solve this problem is,
proc f1 {} {
return "ABC | 0"
}
At the time of calling i need extract both value like,
set console_msg [lindex [split [f1] "|"] 0]
set retval [lindex [split [f1] "|"] 1]
Is there a proper way to do it in TCL?
Thanks,

This may seem obvious to you in hindsight:
set value [f1]
and to assign to variables:
lassign [split $value |] msg val

Related

TCL coding style while creating lists from other list entries

I have the following lines of code:
set FxGlob [lindex $GlobSectionForces $i]
set FyGlob [lindex $GlobSectionForces $i+1]
set FzGlob [lindex $GlobSectionForces $i+2]
set GlobForces [ list $FxGlob $FyGlob $FzGlob ]
That looks uggly to me. I know I could put it all into one set command, not much better.
Is there a "nicer" or "cleaner" way for this?
something like this? Uses lrange to strip the list to the 3 values you want and then use lassign to extract those.
set GlobForces [lrange $GlobSectionForces $i $i+2]
lassign $GlobForces FxGlob FyGlob FzGlob

How to keep the spaces in a string while doing for loop in tcl

HI I have a string like { Its A Very Good Day! Isn't It }. I have to change all the first letter of every word to lower case but the spaces should also be there. For changing to upper case I have used the following code but I do not know how to include the spaces as well.
The code is:
set wordlist { Its A Very Good Day! Isn't It }
set newlistupper [list]
for {set i 0} {$i < [llength $wordlist]} {incr i} {
set word [lindex $wordlist $i]
set newupper [string toupper $word 0 0]
lappend newlistupper $newupper
}
puts $newlistupper
I want to know how to keep the spaces also in the output. Please help.
I would modify your current script a little bit like so:
set wordlist { Its A Very Good Day! Isn't It }
set newlistlower [list]
foreach word [regexp -inline -all -- {\W+|\w+} $wordlist] {
set newlower [string tolower $word 0 0]
lappend newlistlower $newlower
}
puts [join $newlistlower ""]
[regexp -inline -all -- {\W+|\w+} $wordlist] splits the string into word and non-word characters, which means you get to keep spaces and punctuations and so on.
foreach allows you to get each word (spaces get into the loop as well, but string tolower won't be affecting them).
This will also work on strings such as:
set wordlist {Its A Very Good Day! Isn't It--RIGHT }
to give:
{its a very good day! isn't it--rIGHT }
(Braces put to show that the trailing space on the right is kept)
You can use a similar technique to my answer for your previous question:
set sentence { Its A Very Good Day! Isn't It }
set lc [subst -nob -nov [regsub -all {\s[[:upper:]]} $sentence {[string tolower "&"]}]]
puts ">$lc<"
> its a very good day! isn't it <
Another way to do it
% regexp -all -inline -indices {\s[[:upper:]]} $sentence
{1 2} {5 6} {7 8} {12 13} {17 18} {22 23} {28 29}
% set lc $sentence
Its A Very Good Day! Isn't It
% foreach match [regexp -all -inline -indices {\s[[:upper:]]} $sentence ] {
set lc [string replace $lc {*}$match [string tolower [string range $lc {*}$match]]]
}
% puts ">$lc<"
> its a very good day! isn't it <

How does one declare that a particular variable is an array?

I am looing for information on google about declaring array in expect but unable to find it.even the witki link for the line is empty.
I know i can set array values like set arr("hh") "hhh" but how do i declare it.
and can i print the whole array using one command or do i have to loop through it to print all the elements.
Or there is no such thing as declaring array in expect/tcl.i mean can we access any array
just by using global keyword.
You don't have to declare an array, but if you want to:
array set variableName {}
The last word is an empty list. If you have some default values you want to store in the array, you can say:
array set varname {key1 val1 key2 val2 ... ...}
If you're curious, here's how parray is implemented:
proc parray {a {pattern *}} {
upvar 1 $a array
if {![array exists array]} {
error "\"$a\" isn't an array"
}
set maxl 0
set names [lsort [array names array $pattern]]
foreach name $names {
if {[string length $name] > $maxl} {
set maxl [string length $name]
}
}
set maxl [expr {$maxl + [string length $a] + 2}]
foreach name $names {
set nameString [format %s(%s) $a $name]
puts stdout [format "%-*s = %s" $maxl $nameString $array($name)]
}
}
You don't declare arrays in Expect (or Tcl in general) you just use them.
But arrays and other variables do have scope. If you are in a proc and want to
refer to an array arr which has global scope you can either say global arr before
using it or prefix the name with :: each time you use it, eg. set ::arr(hh) "hhh"; puts $::arr(hh).
There is a command parray to print a whole array, but this is loaded from library scripts rather than being built-in, so may not be available depending on how your Expect installation has been done. Eg.
expect1.1> set arr(a) ACBD
ACBD
expect1.2> set arr(b) "BBB bbb"
BBB bbb
expect1.3> parray arr
arr(a) = ACBD
arr(b) = BBB bbb

How to return unmatched string in expect

In my script I want to return the string that does not match .
I tried puts $expect_out(buffer) but it did not work and gave me below error
can't read "expect_out(buffer)": no such variable
while executing
"puts "out is $expect_out(buffer)" "
code
expect {
-nocase -re "$arg3" { exit 0 }
timeout { puts "Does not matched, output is $expect_out(buffer)" ; exit 2 }"
}
The expect_out array doesn't exist until a match occurs, so if you haven't matched an expect call in your code previously and you actually reach your timeout clause, you receive the no such variable error.
Expect manpage
"Upon matching a pattern (or eof or full_buffer), any matching and previously unmatched output is saved in the variable expect_out(buffer). Up to 9 regexp substring matches are saved in the variables expect_out(1,string) through expect_out(9,string). If the -indices flag is used before a pattern, the starting and ending indices (in a form suitable for lrange) of the 10 strings are stored in the variables expect_out(X,start) and expect_out(X,end) where X is a digit, corresponds to the substring position in the buffer. 0 refers to strings which matched the entire pattern and is generated for glob patterns as well as regexp patterns."
You can test this via info exists expect_out and printing out the array keys/values (if it exists) using array names expect_out.
You can set the values explicity yourself via set expect_out(key) value, but there's no way (that I know of) to retrieve the non-matching string initially, bar using log_file expectoutput.txt and reading it back in if you timeout.

TCL array values updation based on command line argument

I am trying to substitute variable value inside array so as to update array values based on command line inputs.
e.g. I am receiving IP address as command line argument for my TCL script and trying to update commands with recvd IP value.
My array is:
array set myArr { 1 myCmd1("192.268.2.1","abc.txt")
2 myCmd2("192.268.2.1","xyz.txt")
3 myCmd3("192.268.2.1","klm.txt")
}
Here, "192.268.2.1" will actually be supplied as command line argument.
I tried doing
array set myArr { 1 myCmd1($myIP,"abc.txt")
2 myCmd2($myIP,"xyz.txt")
3 myCmd3($myIP,"klm.txt")
}
and other combinations like ${myIP}, {[set $myIP]} but none is working.
Thanks in advance for any help/inputs.
Use the list command
% set myIP 0.0.0.0
0.0.0.0
% array set myArr [list 1 myCmd1($myIP,"abc.txt") 2 myCmd2($myIP,"xyz.txt") 3 myCmd3($myIP,"klm.txt")]
% puts $myArr(1)
myCmd1(0.0.0.0,"abc.txt")
% puts $myArr(3)
myCmd3(0.0.0.0,"klm.txt")
%
I think your code will be easier to understand and easier to maintain if you don't try to use array set in this instance. You can get away with it if you are careful (see answers related to using list) but there's really no reason to do it that way when a more readable solution exists.
Here's my solution:
set myArr(1) "myCmd1($myIP,\"abc.txt\")"
set myArr(2) "myCmd2($myIP,\"xyz.txt\")"
set myArr(3) "myCmd3($myIP,\"klm.txt\")"
try:
array set myArr [list myCmd1($myIP, "abc.txt") 2 myCmd2($myIP, "xyz.txt") ... ]
Why? Because when you write {$var} in Tcl, it means $var and not the contents of the variable var. If you use list to create the list instead of the braces, variables are still evaluated.

Resources