Reputation: 1141
Is it possible to change the text from redirected output?
For example, consider this code:
set status [catch {eval exec $executableName $options >@ stdout} errorMessage]
if { $status != 0 } {
return -code error $errorMessage
}
So if there is a "inside" puts
let's suppose: Hello world
, is it possible to print it out Hello tcl
?
So I would like to do something like this:
catch {eval exec $executableName $options} allPuts
regsub -all "hello world" $errorMessage "hello tcl" allPuts
puts $allPuts
But in this solution inside puts
does not printed on the fly
Upvotes: 0
Views: 249
Reputation: 137567
When you use exec $executable {*}$options >@ stdout
(a safer version of what you're using that is preferred for reasons that have nothing to do with your question), you are asking for the output of the subprocess to be sent straight to the outer process's standard output with no further processing. If you want to process things more first, you have to either direct the output through a filtering process before directing it to stdout or to bring it into the outer process for processing.
In this case, we're using the Unix program sed
to do the filtering:
exec $executable {*}$options | sed {s/world/tcl/} >@ stdout
There are many options for doing this sort of thing; any of the many recipes for sed
will (probably) work, so long as you remember that you are using Tcl syntax for exec
and not shell syntax, so instead of sed 's/world/tcl/'
you use sed {s/world/tcl/}
.
If you prefer shell syntax, you do this:
set filter "sed 's/world/tcl/'"
exec $executable {*}$options | sh -c $filter >@ stdout
The script in $filter
is pure Bourne shell.
You can also do the transform inside Tcl. To do that on the fly, you need to work asynchronously on an opened pipeline.
# Define this procedure somewhere
proc transformLine {chan transform} {
if {[gets $chan line] >= 0} {
puts [string map $transform $line]
} elseif {[eof $chan]} {
catch {close $chan} ::doneWithPipe
}
}
set pipe [open "|$executableName $options"]
fileevent $pipe readable [list transformLine $pipe {"world" "tcl"}]
vwait ::doneWithPipe
return -code error $::doneWithPipe
Note that you have to run the event loop (with vwait
) for this to work.
Upvotes: 2