Why the subst command only does variable substitution in my case? [duplicate] - tcl

This question already has answers here:
TCL subst or eval command is not working in my case ..
(3 answers)
Closed 9 years ago.
Tcl's subst command should do command , variable , backslash substitution .
proc sum {a b} {
return [expr $a+$b]
}
%
% set a 1
1
% set b 2
2
subst {sum {$a} {$b}}
subst command should do the variable and command subsdtitutions , Here why command substitution not happend .
sum {1} {2}
subst command should do the variable and command subsdtitutions , Here why command substitution not happend . why it is only substituting the variables ?

Command substitution will look for the pattern [...] and replace it with the returned result of the command inside the brackets, but your string doesn't have any text that matches that pattern.

Related

subst variable names with "point" [duplicate]

This question already has an answer here:
Double variable substitution in tcl
(1 answer)
Closed 3 months ago.
Let's say I have this code :
set a 1
set a.b a
set thing a.b
puts [subst $$thing]
The answer I would expect on the last line would be "a", but tcl answers 1.b
I tried to put \ everywhere before the . but it didn't changed anything.
Is there away to get a from thing variable ?
Tcl does not double evaluate two consecutive dollar signs.
The $thing characters in your command subst $$thing are first replaced by the value of $thing, which is a.b.
Subsequently, the subst command is evaluated like this:
subst $a.b
The above subst command replaces $a with 1, which explains why you get 1.b returned.
A reliable way to do multiple variable interpolation is with the set command without a second argument. Chain together multiple set commands to interpolate multiple times.
puts [set thing]
--> a.b
puts [set [set thing]]
--> a
puts [set [set [set thing]]]
--> 1

TCL - feeding STDIN to exec

I'm trying to implement a retry mechanism when executing an external program using TCL. I'm having some issues when trying to feed STDIN to the external program. I'm now working with a simplified example trying to solve the issue. Take the following python script (simple.py):
x = raw_input()
y = raw_input()
print x + y
Inputs 2 strings from the output will be the concatenation result of the strings.
Now the following command works from the TCL interpreter:
% exec python stuff.py << 1\n2
12
However when I try to split it in separate commands, or add them to a string before doing this, it fails.
Fail 1:
% set cmd "python simple.py << 1\n2"
% exec $cmd
couldn't execute "python simple.py << 1
2": no such file or directory
Fail 2:
% set cmd1 "python simple.py"
% set cmd2 "1\n2"
% exec $cmd1 << $cmd2
couldn't execute "python simple.py": no such file or directory
Fail 3:
% set fullCommandString "exec python simple.py << 1\n2"
% eval $fullCommandString
Traceback (most recent call last):
File "simple.py", line 2, in <module>
y = raw_input()
EOFError: EOF when reading a line
The 3rd case seems that starts the script, but it interprets both lines of STDIN as one.
Any help is appreciated.
Tcl's commands do not reinterpret whitespace in their arguments by default. exec is one of these, and it follows the same rules. That means that you need to tell Tcl to interpret that list of words as a list of words as otherwise it is just a string. Fortunately, there's {*} for this; the expansion operator syntax interprets the rest of the word as a Tcl list, and uses the words out of that list at the point where you write it. It's very useful I find.
The simplest to fix is actually your second case:
% set cmd1 "python simple.py"
% set cmd2 "1\n2"
% exec {*}$cmd1 << $cmd2
You can fix the first and third by adding Tcl list quoting to ensure the 1\n2 is still interpreted as a single word (as otherwise newline is a perfectly reasonable list item separator).
% set cmd "python simple.py << {1\n2}"
% exec $cmd
% set fullCommandString "exec python simple.py << {1\n2}"
% eval $fullCommandString
The third can be written more economically though:
% set fullCommandString "exec python simple.py << {1\n2}"
% {*}$fullCommandString
As a rule of thumb, if you see eval in modern Tcl (note: not namespace eval or interp eval or uplevel) then it's usually an indication that some code could be made more efficient and to have fewer bugs by switching to using expansion carefully.
tl;dr: Put {*} before $cmd1 in your second example to get the idiomatic fix.

Using globs in Perl replace one liner in TCL script

I want to run one Perl one liner in TCL script as below:
exec perl -i -pe {s/SUBSTRING/REPLACING_STRING/g} testFile;
This works fine. But, if I want to modify all the files like below:
exec perl -i -pe {s/SUBSTRING/REPLACING_STRING/g} *;
it gives me the error message:
Can't open '*': No such file or directory.
while executing
exec perl -i -pe {s/SUBSTRING/REPLACING_STRING/g} *;
I tried bracing the '*', but did not solve the problem. Requesting for help...
Assuming that the files a, b, and c are present in the current working directory, executing echo * in the shell prints a b c. This is because the shell command evaluator recognizes wildcard characters and splices in a list of zero or more file names where the wildcard expression was found.
Tcl's command evaluator does not recognize wildcard characters, but passes them unsubstituted to the command that was invoked. If that command can work with wildcards it will do so. The exec command doesn't, which means it will pass the wildcard expression as is to the shell command named by the command string.
Testing this, we get
% exec echo *
*
because what we asked the shell to execute was simply
echo *
If we want a wildcard expression expanded to a list of file names, we need an explicit call to the glob command:
% exec echo [glob *]
"a b c"
which still isn't quite right, since the list wasn't automatically spliced into the command string: instead the shell got
echo {a b c}
(Note: I’m faking echo on Windows here, the actual output might be different.)
To both expand and splice the list of file names, we need this:
% exec echo {*}[glob *]
a b c
The {*} prefix tells the Tcl command evaluator to substitute the following argument as if the words resulting from it were arguments in the original command line.
echo a b c
This example, with a more concise explanation than I've given here, is in the documentation for exec:
"If you are converting invocations involving shell globbing, you should remember that Tcl does not handle globbing or expand things into multiple arguments by default. Instead you should write things like this:"
exec ls -l {*}[glob *.tcl]
PS:
If one has loaded the fileutil package:
package require fileutil
this can be written as a one-liner in Tcl too:
foreach file [glob *] {::fileutil::updateInPlace $file {apply {str {regsub -all SUBSTRING $str REPLACING_STRING}}}}
or with line breaks and indentation for readability:
foreach file [glob *] {
::fileutil::updateInPlace $file {
apply {str {
regsub -all SUBSTRING $str REPLACING_STRING
}}
}
}
Documentation: apply, exec, fileutil package, foreach, glob, package, regsub, {*}

Using $variable in Parenthesis in Tcl (proc)

A part of my code in tcl is:
proc Frame {columnLine} {
.
.
.
}
Now I want use $variable in parenthesis. For example:
set x 2.
set columnLine {$x 5. 10. 15.}
However, after running Tcl, I face an error! How I do solve this problem?
Tcl does not do substitutions on things inside {braces}. If you want substitutions, you've got to either put the overall word inside "double quotes", or use the subst command:
set x 2.
set columnLine [subst {$x 5. 10. 15.}]
set x 2.
set columnLine "$x 5. 10. 15."
One advantage of using subst is that you can pick to just substitute variables and leave backslashes and [bracketed command calls] alone. This is sometimes very useful indeed.
set x 2.
set columnLine [subst -nobackslashes -nocommands {$x 5. 10. 15.}]

TCL subst or eval command is not working in my case ..

subst or eval command is not working in my case ..
% proc sum {a b} {
return [expr $a+$b]
}
%
% set a 1
1
% set b 2
2
% sum $a $b
3
%
% sum {$a} {$b}
can't use non-numeric string as operand of "+"
%
% subst [sum {$a} {$b}]
can't use non-numeric string as operand of "+" >>>>>>>>> Why i am unable to substitue the value
%
% eval [sum {$a} {$b}]
can't use non-numeric string as operand of "+" >>>>>>>>> Why i am unable to substitue the value
%
I want to know why the above cases are not working for me .. subst command should do the variable and command substitution . But why my variables are not substituting.
Can anyone Please Explain what is going on?
First, you do understand why “$a“ isn't a value you can add to? It's not a number at all. (I don't mean $a, the instruction to read from a variable and substitute it, I mean the string consisting of a $ followed by an a.)
When you put braces round things in Tcl, it means “don't do anything with this string at all; use it as-is”. Always. (Sometimes you're feeding that string into a command that evaluates, but not always.) When you put square brackets round things, it means evaluate that string as a script immediately and use the result of the script as the value to substitute. Always.
When you do:
subst [sum {$a} {$b}]
You need to understand that the call to sum is done while assembling the arguments to subst. That call produces an error, so the call to subst never happens. Similarly with the eval form you used.
If we use a somewhat less surprising form:
subst {sum {$a} {$b}}
Then you'll get this out: sum {1} {2}. subst doesn't understand the overall string as a script. On the other hand, with:
eval {sum {$a} {$b}}
In this case you get an error not from the eval as such, but rather from the fact that the call to sum inside is still erroneous.
I suppose you could do:
eval [subst {sum {$a} {$b}}]
But really don't. There's got to be a simpler and less error-prone way.
You put the square braces [] to the wrong place (resp. you even don't need them in the eval case). In the way you wrote the commands the sum {$a} {$b}] is evaluated before the subst or eval command could evaluate the contents of $a and $b.
Correct is:
eval sum {$a} {$b}
or
sum [subst {$a}] [subst {$b}]
You don't understand Tcl correctly.
subst takes a string and substitues all variables in it, right.
But you pass the result of sum {$a} {$b} into it, which fails.
So you could either subst each parameter before you call sum:
sum [subst {$a} {$b}]
Or modify the sum to do the evaluation for you:
proc sum {a b} {
uplevel 1 [list expr $a + $b]
}
expr does an own round of evaluation, this is why you usually pass a litteral string (enclosed with {}) to it, but in this case we actually use this fact. uplevel executes the command in the context of the caller.
If you call a command, Tcl will replace the variables before the actuall call is made, so maybe this snippet could help you to understand Tcl a little bit better:
set a pu
set b ts
$a$b "Hello World!"