TCL获取Exec&x27的日志;d过程

TCL获取Exec&x27的日志;d过程,tcl,Tcl,目前我正在按照命令开火 set pid [exec make &] set term_id [wait pid] 第一个命令将在TCL内部执行makefile,第二个命令将等待第一个命令的makefile操作完成First命令显示标准输出上makefile的所有日志。当exec的最后一个参数使用重定向或任何其他方法给出“&”时,是否可以将所有日志存储在变量或文件中 如果没有给出“&”,那么我们可以使用 set log [exec make] 但如果给出了“&”,则命令将返回进程id

目前我正在按照命令开火

set pid [exec make &]

set term_id [wait pid]
第一个命令将在TCL内部执行makefile,第二个命令将等待第一个命令的makefile操作完成First命令显示标准输出上makefile的所有日志。当exec的最后一个参数使用重定向或任何其他方法给出“&”时,是否可以将所有日志存储在变量或文件中

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

set log [exec make]
但如果给出了“&”,则命令将返回进程id

set pid [exec make &]

因此,是否可以停止
stdout
日志并将其放入变量中?

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

lassign [chan pipe] reader writer
set pid [exec make >@$writer &]
close $writer
不要忘记从
$reader
读取,否则子进程将暂停。请注意,以这种方式使用时,输出将被完全缓冲,尽管这在执行交互工作时更为重要。如果您希望输出也回显到standard out,则需要让脚本这样做。这里有一个简单的阅读器处理程序

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 |…
pipeline表单),因此您希望保持事件循环继续。那很好。这正是
fileevent
的作用,但您必须异步思考

本例不使用非阻塞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(以及更高版本,一旦我们使用更高版本)的功能,因为它们依赖于无堆栈执行引擎。

让我重新表述我的问题,我使用的是8.5。。。我的make操作在stdout上生成大量日志,并显示gui。。是否可以在变量上传输该值?如果没有“&”,我的日志和GUI在exec中是不可见的?在Tcl 8.5中,如果您也有TclX扩展(或可以安装它),但替换了Tcl 8.6内置的
chan pipe
,您仍然可以使用Donal的第一个解决方案。@AxT_8041查看我的扩展版本的答案。它应该涵盖你需要的一切。
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
}