TCL-获取Exec进程的日志

时间:2016-01-25 09:36:36

标签: tcl

目前我正在按照命令

开火
set pid [exec make &]

set term_id [wait pid]

第一个命令将在TCL内执行makefile,第二个命令将等待第一个命令的makefile操作完成。 第一个命令在stdout上显示makefile的所有日志。当"&"是否可以将所有日志存储在变量或文件中?在exec的最后一个参数中使用重定向或任何其他方法给出?

如果"&"没有给出,那么我们可以使用

来获取输出
set log [exec make]

但是如果"&"给出然后命令将返回进程ID,

set pid [exec make &]

那么可以停止stdout日志并将它们放在变量中吗?

1 个答案:

答案 0 :(得分:2)

如果您使用的是Tcl 8.6,则可以使用以下方法捕获输出:

lassign [chan pipe] reader writer
set pid [exec make >@$writer &]
close $writer

不要忘记从$reader读取或子进程将停止。请注意,以这种方式使用时,输出将完全缓冲,但这在进行交互式工作时更为重要。如果您希望输出回显到标准输出,则需要使脚本执行此操作。这是一个简单的读者处理程序。

while {[gets $reader line] >= 0} {
    lappend log $line
    puts $line
}
close $reader

在Tcl 8.6之前,最好的办法是创建一个子进程命令管道:

set reader [open |make]

如果你需要PID,这可能会变得有点复杂:

set reader [open |[list /bin/sh -c {echo $$; exec make}]]
set pid [gets $reader]

是的,那太丑了......

[编辑]:你在Tcl 8.5中使用Tk(所以你需要上面的open |…管道表格),所以你想保持事件循环。没关系。这正是fileevent的用途,但你必须异步思考

# This code assumes that you've opened the pipeline already
fileevent $reader readable [list ReadALine $reader]
proc ReadALine {channel} {
    if {[gets $channel line] >= 0} {
        HandleLine $line
    } else {
        # No line could be read; must be at the end
        close $channel
    }
}
proc HandleLine {line} {
    global log
    lappend log $line;     # Or insert it into the GUI or whatever
    puts $line
}

此示例使用非阻塞I / O. 可能导致问题,但可能不会。如果它确实导致问题,请使用:

fconfigure $reader -blocking 0
fileevent $reader readable [list ReadALine $reader]
proc ReadALine {channel} {
    if {[gets $channel line] >= 0} {
        HandleLine $line
    } elseif {[eof $channel]} {
        close $channel
    }
}
proc HandleLine {line} {
    global log
    lappend log $line
    puts $line
}

更复杂和多功能的版本是可能的,但只有在处理不受信任的渠道(例如,公共服务器套接字)时才真正需要它们。

如果你一直在使用8.6,你可以使用协同程序使这段代码看起来更像我之前使用的直线代码,但它们是一个严格的8.6(之后,我们做的)仅仅因为它们依赖于无堆栈执行引擎。