目前我正在执行以下命令
set pid [exec make &]
set term_id [wait pid]
第一个命令将在TCL内部执行makefile,第二个命令将等待第一个命令的makefile操作完成。 第一个命令在标准输出上显示 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
中读取,否则子进程将停止。请注意,以这种方式使用时,输出将以完全缓冲的方式传递,尽管这在进行交互式工作时更为重要。如果您还希望输出回显为标准输出,则需要让您的脚本执行此操作。这是一个简单的读取器处理程序。
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
}
更复杂和通用的版本是可能的,但只有当您处理不受信任的 channel (例如公共(public)服务器套接字)时,它们才是真正必要的。
如果您一直在使用 8.6,您可以使用协程来使此代码看起来更类似于我之前使用的直线代码,但它们是严格的 8.6 功能(后来,一旦我们这样做了)更高版本)仅因为它们依赖于无堆栈执行引擎。
关于TCL-获取执行进程的日志,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34989209/