0

是否可以从重定向输出中更改文本?

例如,考虑以下代码:

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并没有即时打印

4

1 回答 1

2

当您使用(由于与您的问题无关exec $executable {*}$options >@ stdout的原因而首选您正在使用的更安全的版本)时,您要求将子进程的输出直接发送到外部进程的标准输出,而无需进一步加工。如果您想先处理更多内容,则必须先通过过滤过程引导输出,然后再将其引导到 stdout,或者将其带入外部进程进行处理。

构建过滤管道

在这种情况下,我们使用 Unix 程序sed进行过滤:

exec $executable {*}$options | sed {s/world/tcl/} >@ stdout

做这种事情有很多选择;sed只要您记得您使用的是 Tcl 语法exec而不是 shell 语法,那么许多方法中的任何一种都将(可能)起作用,所以不要sed 's/world/tcl/'使用sed {s/world/tcl/}.

如果您更喜欢 shell 语法,请执行以下操作:

set filter "sed 's/world/tcl/'"
exec $executable {*}$options | sh -c $filter >@ stdout

中的脚本$filter是纯 Bourne shell。

Tcl 内部处理

您也可以在 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)才能使其正常工作。

于 2013-08-26T10:18:08.627 回答