是否可以从重定向输出更改文本?
例如,请考虑以下代码:
set status [catch {eval exec $executableName $options >@ stdout} errorMessage]
if { $status != 0 } {
return -code error $errorMessage
}
所以,如果有一个"内部" puts
让我们假设:Hello world
,是否可以将其打印出来Hello tcl
?
所以我想做这样的事情:
catch {eval exec $executableName $options} allPuts
regsub -all "hello world" $errorMessage "hello tcl" allPuts
puts $allPuts
但在此解决方案中,puts
内部不会立即打印
答案 0 :(得分:2)
当您使用exec $executable {*}$options >@ stdout
(由于与您的问题无关的原因而使用的更安全版本的首选项时),您要求输出子进程直接发送到外部进程的标准输出而无需进一步处理。如果您想先处理更多事情,则必须先将输出定向到过滤过程,然后再将其引导到stdout或将其带入外部流程进行处理。
在这种情况下,我们使用Unix程序sed
进行过滤:
exec $executable {*}$options | sed {s/world/tcl/} >@ stdout
有很多选择可以做这种事情; sed
的许多配方中的任何一个(可能)都可以工作,只要你记得你使用的是exec
的Tcl语法而不是shell语法,那么你使用sed 's/world/tcl/'
代替sed {s/world/tcl/}
{1}}。
如果您更喜欢shell语法,请执行以下操作:
set filter "sed 's/world/tcl/'"
exec $executable {*}$options | sh -c $filter >@ stdout
$filter
中的脚本是纯粹的Bourne shell。
您也可以在Tcl中进行转换。要在运行中执行此操作,您需要在打开的管道上异步工作。
# 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
请注意, 运行事件循环(使用vwait
)以使其正常工作。