jstraugh
jstraugh

Reputation: 110

How can I edit a line in .tcl file?

I need to run a .tcl file via command line which get invoked with a Python script. However, a single line in that .tcl file needs to change based on input from the user. For example:

info = input("Prompt for the user: ")

Now I need the string contained in info to replace one of the lines in .tcl file.

Upvotes: 0

Views: 1178

Answers (1)

Donal Fellows
Donal Fellows

Reputation: 137597

Rewriting the script is one of the trickier options to pick. It makes things harder to audit and it is tremendously easy to make a mess of. It's not recommended at all unless you take special steps, such as factoring out the bit you set into its own file:

File that you edit, e.g., settings.tcl (simple enough that it is pretty trivial to write and you can rewrite the whole lot each time without making a mess of it)

set value "123"

Use of that file:

set value 0
if {[file readable settings.tcl]} {
    source settings.tcl
}
puts "value is $value"

More sophisticated versions of that are possible with safe interpreters and language profiling… but they're only really needed when the settings and the code are in different trust domains.


That said, there are other approaches that are usually easier. If you are invoking the Tcl script by running a subprocess, the easiest ways to pass an arbitrary parameter are to use one of:

  1. A command line argument. These can be read on the Tcl side from the $argv global, which holds a list of all arguments after the script name. (The lindex and lassign commands tend to be useful here, e.g., set value [lindex $argv 0].)

  2. An environment variable. These can be read on the Tcl side from the env global array, e.g., set value $env(MyVarName)

  3. On standard input. A line can be read from that on the Tcl side using set line [gets stdin].

In more complex cases, you'd pass values in their own files, or by writing them into something like an SQLite database, or… well, there's lots of options.

If on the other hand the Tcl interpreter is in the same process, pass the values by setting the variables in it before asking for the script to run. (Tcl has almost no true globals — environment variables are a special exception, and only because the OS forces it upon us — so everything is specific to the interpreter context.)

Specifically, if you've got a Tcl instance object from tkinter (Tk is a subclass of that) then you can do:

import tkinter

interp = tkinter.Tcl()
interp.call("set", "value", 123)
interp.eval("source program.tcl")
# Or interp.call("source", "program.tcl")

That has the advantage of doing all the quoting for you.

Upvotes: 1

Related Questions