TCL使用-nohang选项获取命令?

TCL使用-nohang选项获取命令?,tcl,stdin,interactive,gets,Tcl,Stdin,Interactive,Gets,下面是一段代码,它只是通过命令提示符MyShell>实现了一个交互式TCL会话 puts -nonewline stdout "MyShell > " flush stdout catch { eval [gets stdin] } got if { $got ne "" } { puts stderr $got } 此代码在终端提示MyShell>,并等待按下回车按钮;虽然没有命中,但代码什么也不做。这就是获取命令的作用 我需要的是gets命令的替代方法,比如coolget。c

下面是一段代码,它只是通过命令提示符
MyShell>
实现了一个交互式TCL会话

puts -nonewline stdout "MyShell > "
flush stdout
catch { eval [gets stdin] } got
if { $got ne "" } {
    puts stderr $got
}
此代码在终端提示
MyShell>
,并等待按下回车按钮;虽然没有命中,但代码什么也不做。这就是
获取
命令的作用

我需要的是
gets
命令的替代方法,比如
coolget
coolget
命令不应该等待回车按钮,而是注册一些在点击时调用的插槽,然后继续执行。所需的代码应如下所示:

proc evaluate { string } \
{
    catch { eval $string } got
    if { $got ne "" } {
        puts stderr $got
    }
}

puts -nonewline stdout "MyShell > "
flush stdout
coolgets stdin evaluate; # this command should not wait for the enter button
# here goes some code which is to be executed before the enter button is hit

以下是我需要的:

proc prompt { } \
{
   puts -nonewline stdout "MyShell > "
   flush stdout
}


proc process { } \
{
   catch { uplevel #0 [gets stdin] } got
   if { $got ne "" } {
       puts stderr $got
       flush stderr
   }
   prompt
}

fileevent stdin readable process

prompt
while { true } { update; after 100 }

我认为您需要查看fileevent、fconfigure和vwait命令。使用这些,您可以执行以下操作:

proc GetData {chan} {
    if {[gets $chan line] >= 0} {
       puts -nonewline "Read data: "
       puts $line
    }
}

fconfigure stdin -blocking 0 -buffering line -translation crlf
fileevent stdin readable [list GetData stdin]

vwait x

这段代码将GetData注册为stdin的可读文件事件处理程序,因此只要有数据可读取,就会调用它。

Tcl将类似“nohang”的功能应用于整个通道,通过将通道配置为非阻塞来完成。在此之后,任何
读取
都将只返回那里的数据,
获取
将只返回无需等待即可使用的完整行,
放置
(在可写通道上)将安排将其输出异步发送到操作系统。这取决于正在运行的事件循环

建议对已注册的文件事件处理程序使用非阻塞通道。您可以将其与非阻塞相结合,以实现您的
coolget
想法:

proc coolget {channel callback} {
    fileevent $channel readable [list apply {{ch cb} {
        if {[gets $ch line] >= 0} {
            uplevel [lappend cb $line]
        } elseif {[eof $ch]} {
            # Remove handler at EOF: important!
            fileevent $ch readable {}
        }
    }} $channel $callback]
}
这样就可以很好地工作了,除了您必须调用
vwait
update
来处理事件(除非您也使用了Tk;Tk是特殊的),因为Tcl不会在后台神奇地处理事情;神奇的背景处理带来的麻烦太多了


<>如果你在异步事件处理中陷入了深深的纠结,请考虑使用TCL 8.6来重新构造代码。特别是像这样的代码可以帮助很多。然而,这在很大程度上依赖于Tcl 8.6,因为早期的Tcl实现根本不支持协同路由;底层实现必须从简单的C调用重写为continuations来启用这些特性,这是不可能的