Reputation: 17
I'm launching a single EXE from a Tcl script, and would like to get the output from the EXE and display it using a simple PUTS command to provide user feedback. At the moment, I am launching the EXE in a CMD window where the user can see the progress, and waiting for the EXE to create a file. The first script here works whenever the output file LUC.CSV is created.
file delete -force luc.csv
set cmdStatus [open "| cmd.exe /c start /wait uc.exe"]
while {![file exists "luc.csv"]} {
}
# continue after output file is created
However, sometimes the file is not created, so I can't rely on this method.
I've been trying to get my head around the use of fileevent and pipes, and have tried several incarnations of the script below, but I'm obviously either missing the point or just not getting the syntax right.
puts "starting"
set fifo [open "| cmd.exe /c start uc.exe" r]
fconfigure $fifo -blocking 0
proc read_fifo {fifo} {
puts "calling read_fifo"
if {[gets $fifo x] < 0} {
if {[eof $fifo]} {
close $fifo
}
}
puts "x is $x"
}
fileevent $fifo readable [list read_fifo $fifo]
vwait forever
puts"finished"
Any help would be greatly appreciated!
Upvotes: 0
Views: 308
Reputation: 137567
If you just want to launch a subprocess and do nothing else until it finishes, Tcl's exec
command is perfect.
exec cmd.exe /c start /wait uc.exe
(Since you're launching a GUI application via start
, there won't be any meaningful result unless there's an error in launching. And in that case you'll get a catch
able error.) Things only get complicated when you want to do several things at once.
To make your original code work, you have to understand that the subprocess has finished. Tcl's just vwait
ing forever
because your code says to do that. We need to put something in to make the wait finish. A good way is to make the wait be for something to happen to the fifo
variable, which can be unset after the pipe is closed as it no longer contains anything useful. (vwait
will become eligible to return once the variable it is told about is either written to or destroyed; it uses a variable trace under the covers. It also won't actually return until the event handlers it is currently processing return.)
puts "starting"
# ***Assume*** that this code is in the global scope
set fifo [open "| cmd.exe /c start uc.exe" r]
fconfigure $fifo -blocking 0
proc read_fifo {} {
global fifo
puts "calling read_fifo"
if {[gets $fifo x] < 0} {
if {[eof $fifo]} {
close $fifo
unset fifo
}
}
puts "x is $x"
}
fileevent $fifo readable read_fifo
vwait fifo
puts "finished"
That ought to work. The lines that were changed were the declaration of read_fifo
(no variable passed in), the adding of global fifo
just below (because we want to work with that instead), the adding of unset fifo
just after close $fifo
, the setting up of the fileevent
(don't pass an extra argument to the callback), and the vwait
(because we want to wait for fifo
, not forever
).
Upvotes: 1