TCL coding style while creating lists from other list entries - coding-style

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

Related

How to count from 1 to 50 and set each number as a variable in Batch file?

Good Day, I here a batch script that uses a function to operate
#echo off
setlocal enableDelayedExpansion
:INSTALLER
set "n1=7_Zip"
set "n2=Adobe_Products"
set "n3=Allavsoft"
set "n4=Astute_Graphics"
set "n5=AutoHotkey"
set "n6=Backup_and_Sync_from_Google"
set "n7=BlueStacks_5_Beta"
set "n8=CC_Cleaner"
set "n9=Core_Temp"
set "n10=CPUID_CPU-Z"
I'm having trouble because I want the variable n1 n2...10 to be dependent, Meaning I want it to be like this !n%c%! (where %c%is the number after n) so when I insert a new program between 2 programs the numbering will be moved. For example, I will insert the Notepad++ between CC_cleaner and Core_Temp. Now when I insert the Notepad++ its number will be the Old number of Core_Temp which is 9 and the New number of Core_Temp will be 10 and the New number of the CPUID_CPU-Z will be 11. I just can't figure out where I can get the variable 1 2 ... 11 to be substituted to the value of %c%. I'm thinking of a for loop that will count from 1 to 50 and set each number as a variable so I can Substitute those variables for the value of %c% but I don't know how to make it.
I'm also open to other options aside from for loop
use a function to define the array. In doing so, new values only need to be added to the list of parameter values the function is called with.
Edit: I'm not sure whats unclear given the usage example provided and the description of the argument structure of the function, so heres a desciption of the functionality of the function:
In your opening question, you manually define an array with the prefix n followed by numeric indexes one at a time:
set "n1=7_Zip"
set "n2=Adobe_Products"
set "n3=Allavsoft"
set "n4=Astute_Graphics"
set "n5=AutoHotkey"
set "n6=Backup_and_Sync_from_Google"
set "n7=BlueStacks_5_Beta"
set "n8=CC_Cleaner"
set "n9=Core_Temp"
set "n10=CPUID_CPU-Z"
The above method of hard coding each value to an index makes adding values to the beginning / middle of the array time consuming as each n# has to be manually updated.
Rather than hardcoding each value line by line, The function below takes a list (or series of lists) as parameters containing the arrays name (%1, the first argument) and the values to be defined to the array (all other arguments), assigns the list to a variable in order to seperate the array name from the values to be defined, then uses a For loop to iterate over the values, increment the arrays unique index, and then assigns the current value in the list to the appropriate index.
This allows the above definitions to be achieved using the following call:
Call :DefineArray n 7_Zip Adobe_Products Allavsoft Astute_Graphics AutoHotkey Backup_and_Sync_from_Google BlueStacks_5_Beta CC_Cleaner Core_Temp CPUID_CPU-Z
Example output (with Set n.):
n.1=7_Zip
n.10=CPUID_CPU-Z
n.2=Adobe_Products
n.3=Allavsoft
n.4=Astute_Graphics
n.5=AutoHotkey
n.6=Backup_and_Sync_from_Google
n.7=BlueStacks_5_Beta
n.8=CC_Cleaner
n.9=Core_Temp
Notes:
The function defines array variables using an additional . suffix to the arrays prefix name (IE: n.1 n.2 ...). This is done to allow differentiation of the array from other environment variables that begin with the same prefix as the arrays variable name when the Set command is being used.
The function does not zero the index count of the array when called. This allows calls to define values to be spread over multiple lines for easier maintenance and readablity.
#Echo off
:# prepare envarinoment for use of '!' expansion during code blocks
:# '!' expansion allows access of variables whose name contains other variables
:# and provides protection against batch poison characters
Setlocal EnableExtensions EnableDelayedExpansion
:# Calls the label DefineArray with parameters; doublequoting any string containing
:# standard delimiters
Call :DefineArray arrayname value1 "value 2"
:# Display defined variables prefixed with arrayname
Set arrayname
Goto :Eof
:# Function label name and arg structure
:DefineArray groupname list of values
:# Define all paramters to Params with leading whitespace used to remove groupname from parameter list.
Set ^"Params= %*"
:# Remove the groupname from the list of elements to be assigned
Set "Params=!Params: %1 =!"
:# Initialise array index variable specific to the groupname;
:# [If not already incremented]
Set /A "%~1[i]+=0"
:# iterate over Params list; increment group index count; Assign element
:# to groupname.index
For %%G in (!Params!)Do (
Set /A "%~1[i]+=1"
Set "%~1.!%~1[i]!=%%~G"
)
:# exit function
Exit /b 0
Note: The method used above will consume any ! characters present in values due to Delayed expansion.

Getting Logs of Console in Variable in TCL

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

Change a referenced variable in BASH

I am intending to change a global variable inside a function in BASH, however I don't get a clue about how to do it. This is my code:
CANDIDATES[5]="1 2 3 4 5 6"
random_mutate()
{
a=$1 #assign name of input variable to "a"
insides=${!a} #See input variable value
RNDM_PARAM=`echo $[ 1 + $[ RANDOM % 5 ]]` #change random position in input variable
NEW_PAR=99 #value to substitute
ARR=($insides) #Convert string to array
ARR[$RNDM_PARAM]=$NEW_PAR #Change the random position
NEW_GUY=$( IFS=$' '; echo "${ARR[*]}" ) #Convert array once more to string
echo "$NEW_GUY"
### NOW, How to assign NEW_GUY TO CANDIDATES[5]?
}
random_mutate CANDIDATES[5]
I would like to be able to assign NEW_GUY to the variable referenced by $1 or to another variable that would be pointed by $2 (not incuded in the code). I don't want to do the direct assignation in the code as I intend to use the function for multiple possible inputs (in fact, the assignation NEW_PAR=99 is quite more complicated in my original code as it implies the selection of a number depending the position in a range of random values using an R function, but for the sake of simplicity I included it this way).
Hopefully this is clear enough. Please let me know if you need further information.
Thank you,
Libertad
You can use eval:
eval "$a=\$NEW_GUY"
Be careful and only use it if the value of $a is safe (imagine what happens if $a is set to rm -rf / ; a).

compare two variables in a text file

I have a text file with multiple lines every two lines has the foillowing information:
Hostname, IP
IP, Hostname.Domain
What I would like to do is compare line one hostname and line two hostname. If they match I want to copy the hostname to a new text document.
I am new to scripting and would appreciate any help I can get.
if you use .split("\n"), it will give you an array that contain lines
contentLines = content.split("\n");
http://jsfiddle.net/sN6XT/
Than just loop through the array for odd (or even) index, use regex to find the line you want
Hope it helps :D
Something like this should work:
Set fso = CreateObject("Scripting.FileSystemObject")
Set infile = fso.OpenTextFile("C:\path\to\input.txt")
Set outfile = fso.OpenTextFile("C:\path\to\output.txt")
Do Until infile.AtEndOfStream
hostname1 = Trim(Split(infile.ReadLine, ",")(0))
fqdn = Split(infile.ReadLine, ",")(1)
hostname2 = Trim(Split(fqdn, ".")(0))
If LCase(hostname1) = LCase(hostname2) Then outfile.WriteLine hostname1
Loop
infile.Close
outfile.Close

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