目前我正在按照命令
开火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
日志并将它们放在变量中吗?
答案 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(之后,我们做的)仅仅因为它们依赖于无堆栈执行引擎。