I have 5 different variable coming from different if and loop statements, when I use "put" to take output into text file all characters and digits are altogether like this : alphaclass112098voip. where
variables: name = alpha
category = class1
number = 12098
service = voip
I want output in file as like this with spaces on same line.
Alpha class1 12098 voip
Beta class1 12093 DHCP SIP
Also at certain point I want to through delimiters for future purposes.
The easiest way to deal with this is to construct a Tcl list that represents the record. You can do this piecemeal with lappend, or all at once with list. Or mix them.
foreach name $names category $categories number $numbers service $services {
set record [list $name $category]
lappend record $number
lappend record $service
puts $record
}
This shows the record for each line in a format that Tcl finds easy to parse (you'll see what I mean if you have a name with a space in it). To use a delimiter to separate the values instead, the join command is very useful:
puts [join $record $delimiter]
The default delimiter is space, but try a : instead to see how it works.
If you're generating a CSV file, do use the csv package in Tcllib. It handles the tricky edge-cases (e.g., embedded commas) for you.
Related
after doing some other things in my script I end up with a series of variables set in tcl ($sel1, $sel2, $sel3, ...) and I need to add them to the following line:
set all [::TopoTools::selections2mol "$box $sel1 $sel2 $sel3 $sel4"]
Now, if I only had four this would be fine by hand, but in the final version I will have hundreds which is untenable to do by hand. I'm sure the answer is some kind of loop, but I've been giving it some thought now and I can't quite figure it out. If I had, say, $sel1, $sel2, all the way to a given number, how would I add them to that line in the format shown at any amount that I want, with the $box at the beginning as shown? Thanks very much for your help.
It may or may not be relevant, but I define the variables in a loop as follows:
set sel$i [atomselect $id all]
I'm not familiar with the software you are using, but it should be possible to fix this without too much hassle.
If you put this inside the loop instead:
set sell$i [atomselect $id all]
append valueStr " " [set sell$i]
(or perhaps this, even if it is little C:)
append valueStr " " [set sell$i [atomselect $id all]]
you will get the string that " $sel1 $sel2 $sel3 $sel4" is substituted into (remember to put $box in as well).
With Tcl 8.5 or later, you can do
dict set values $i [atomselect $id all]
inside the loop, which gives you a dictionary structure containing all values, and then create the sequence of values with:
set all [::Topotools::selections2mol [concat $box [dict values $values]]]
Depending on the output and input formats of atomselect and selections2mol, the latter might not actually work without a little fine-tuning, but it should be worth a try.
In the latter case, you aren't getting the variables, but each value is available as
dict get $values $i
You can do this with an array also:
set values($i) [atomselect $id all]
but then you need to sort the keys before collecting the values, like this
set valueStr [list $box]
foreach key [lsort -integer [array names values]] {
append valueStr " " $values($key)
}
Documentation:
append,
array,
concat,
dict,
foreach,
list,
lsort,
set
I have a list called parameters and the content of this list can be different but it will look something like:
var1=2;
var2=2'h2;
var3=2'h0;
....
This list comes from reading a file and done some preformating already. I just want to grab the value of var1 and store it in a variable. Eg whatever is in between '=' sign and ';' sign but only for var1 (in this case number 2). Equally I can remove all the lines that are not matching 'var1'.
Assuming your parameters list is already set, you can do something like:
foreach item $parameters {
if {[regexp "var1\\s*=\\s*(\\w+);" $item wholeMatch myVal]} {
break
}
}
puts "value is '$myVal'"
The regular expression I use allows for optional spaces before and after the equal sign. Take a look at Tcl's regex syntax and adjust as necessary.
It might be easier to just do a regex search through your whole file using, rather than parsing your file into a list. But again, take a look at Tcl's documentation.
set_dont_use [get_lib_cells */*CKGT*0P*] -power
set_dont_use [get_lib_cells */*CKTT*0P*] -setup
The above is a text file.
I Want to store */CKGTOP* and */CKTTOP* in to a variable this is the programme which a person helped me with
set f [open theScript.tcl]
# Even with 10 million lines, modern computers will chew through it rapidly
set lines [split [read $f] "\n"]
close $f
# This RE will match the sample lines you've told us about; it might need tuning
# for other inputs (and knowing what's best is part of the art of RE writing)
set RE {^set_dont_use \[get_lib_cells ([\w*/]+)\] -\w+$}
foreach line $lines {
if {[regexp $RE $line -> term]} {
# At this point, the part you want is assigned to $term
puts "FOUND: $term"
}
}
My question is if more than one cells like for example
set_dont_use [get_lib_cells */*CKGT*0P* */*CKOU*TR* /*....] -power
set_dont_use [get_lib_cells */*CKGT*WP* */*CKOU*LR* /*....] -setup
then the above script isn't helping me to store the these "n" number cells in the variable known as term
Could any of u people help me
Thanking you ahead in time
I would go with
proc get_lib_cells args {
global term
lappend term {*}$args
}
proc unknown args {}
and then just
source theScript.tcl
in a shell that doesn't have the module you are using loaded, and thus doesn't know any of these non-standard commands.
By setting unknown to do nothing, other commands in the script will just be passed over.
Note that redefining unknownimpairs Tcl's ability to automatically load some processes, so don't keep using that interpreter after this.
Documentation:
global,
lappend,
proc,
unknown,
{*} (syntax)
Your coding seems like the Synopsys syntax, meaning - it shouldn't work the way you wrote it, I'd expect curly braces:
set_dont_use [get_lib_cells {*/*CKGT*0P* */*CKOU*TR* /*....}] -power
moreover, the \w doesn't catch the *,/ (see this).
If I were you, I'd go for set RE {^set_dont_use \[get_lib_cells \{?([\S*]+ )+\}?\] -\w+$} and treat the resulting pattern match as a list.
Edit:
see this:
% regexp {^set_dont_use [get_lib_cells {?(\S+) ?}?]} $line -> match
1
% echo $match
*/*CKGT*0P*
If you have more than one item in your line, add another parentheses inside the curly braces:
regexp {^set_dont_use \[get_lib_cells \{?(\S+) ?(\S+)?\}?\]} $l -> m1 m2
ect.
Another Edit
take a look at this, just in case you want multiple matches with the same single pattern, but than, instead of \S+, you should try something that looks like this: [A-Za-z\/\*]
Could you please help me with the following script?
It is a Tcl script which Synopsys IC Compiler II will source.
set_dont_use [get_lib_cells */*CKGT*0P*] -power
set_dont_use [get_lib_cells */*CKTT*0P*] -setup
May I know how to take only */*CKGT*0P* and */*CKTT*0P* and assign these to a variable.
Of course you can treat a Tcl script as something you search through; it's just a file with text in it after all.
Let's write a script to select the text out. It'll be a Tcl script, of course. For readability, I'm going to put the regular expression itself in a global variable; treat it like a constant. (In larger scripts, I find it helps a lot to give names to REs like this, as those names can be used to remind me of the purpose of the regular expression. I'll call it “RE” here.)
set f [open theScript.tcl]
# Even with 10 million lines, modern computers will chew through it rapidly
set lines [split [read $f] "\n"]
close $f
# This RE will match the sample lines you've told us about; it might need tuning
# for other inputs (and knowing what's best is part of the art of RE writing)
set RE {^set_dont_use \[get_lib_cells ([\w*/]+)\] -\w+$}
foreach line $lines {
if {[regexp $RE $line -> term]} {
# At this point, the part you want is assigned to $term
puts "FOUND: $term"
}
}
The key things in the RE above? It's in braces to reduce backslash-itis. Literal square brackets are backslashed. The bit in parentheses is the bit we're capturing into the term variable. [\w*/]+ matches a sequence of one or more characters from a set consisting of “standard word characters” plus * and /.
The use of regexp has -> as a funny name for a variable that is ignored. I could have called it dummy instead; it's going to have the whole matched string in it when the RE matches, but we already have that in $term as we're using a fully-anchored RE. But I like using -> as a mnemonic for “assign the submatches into these”. Also, the formal result of regexp is the number of times the RE matched; without the -all option, that's effectively a boolean that is true exactly when there was a match, which is useful. Very useful.
To assign the output of any command <command> to a variable with a name <name>, use set <name> [<command>]:
> set hello_length [string length hello]
5
> puts "The length of 'hello' is $hello_length."
The length of 'hello' is 5.
In your case, maybe this is what you want? (I still don't quite understand the question, though.)
set ckgt_cells [get_lib_cells */*CKGT*0P*]
set cktt_cells [get_lib_cells */*CKTT*0P*]
I have to print multiple variables in a single puts like this
puts "$n1_$n2_$n3_$n4"
where n1 , n2 , n3 , n4 are 4 variables.
It wont print and will show error n1_ : no such variable
Expected output should be something like this (example)
01_abc_21_akdd
Variable names in Tcl can be any string in Tcl, there are no restrictions but if you want to use special characters (those not in the range of a-z, 0-9 and _, and letters in different languages depending on the platform and locale), you have to either brace the expression names or use other workarounds (like with the answer of Hoodiecrow).
What this means is that if you have a variable named abc.d, and if you use $abc.d, the Tcl engine will try to find the variable $abc because . is not a 'normal' character.
But if you have a variable named abc and use $abcd, or $abc_d, then the engine will start looking for the variables abcd or abc_d and not abc.
Because of this, you will have to use braces between the variable name for example:
${n1}
The reason why putting a backslash works is that \ is not a 'normal' character and after reading the above, it should be a little more obvious how things worked.
There are a few things that yet can go in variable names which don't need bracing and still mean something, except that something is 'special':
::: This is usually used for scoping purposes. For instance if you have a global variable named my_var, you can also use $::my_var to refer to it. Here :: tells Tcl that my_var is a global variable. Note that if there are more than two : in a row they will not add up:
% set ::y 5
5
% set ::::y
5
% set :::y
5
:: is usually used to define the namespace the variable is in. For example, $mine::var is a variable called var in the namespace with a name of mine.
(): These are used for arrays. $arr(key) is a variable with two parts: the array name arr and the key name key. Note: you can have an array named and a key named because...
% set () abc
abc
% puts $()
abc
% array get ""
{} abc
There might be some more, but those are the basics you could look out for.
Two other ways:
puts "${n1}_${n2}_${n3}_${n4}"
puts [format "%s_%s_%s_%s" $n1 $n2 $n3 $n4]
Documentation: format
(Note: the 'Hoodiecrow' mentioned in Jerry's answer is me, I used that nick earlier.)