如何更改重定向输出?

时间:2013-08-26 06:35:13

标签: tcl

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

例如,请考虑以下代码:

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内部不会立即打印

1 个答案:

答案 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

内处理

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