虽然我对Tcl非常熟悉,但这是一个初学者的问题。我想从管道读取和写入。我想在纯Tcl中使用解决方案而不使用像Expect这样的库。我从tcl wiki复制了一个例子,但无法让它运行。
我的代码是:
cd /tmp
catch {
console show
update
}
proc go {} {
puts "executing go"
set pipe [open "|cat" RDWR]
fconfigure $pipe -buffering line -blocking 0
fileevent $pipe readable [list piperead $pipe]
if {![eof $pipe]} {
puts $pipe "hello cat program!"
flush $pipe
set got [gets $pipe]
puts "result: $got"
}
}
go
输出为executing go\n result:
,但我希望从管道中读取一个值会返回我发送给cat程序的行。
我的错误是什么?
-
编辑:
我跟着potrzebie的回答,得到了一个小例子。这足以让我走了。测试我的设置的快速解决方法是以下代码(不是真正的解决方案,而是目前的快速修复)。
cd /home/stephan/tmp
catch {
console show
update
}
puts "starting pipe"
set pipe [open "|cat" RDWR]
fconfigure $pipe -buffering line -blocking 0
after 10
puts $pipe "hello cat!"
flush $pipe
set got [gets $pipe]
puts "got from pipe: $got"
答案 0 :(得分:2)
写入管道并进行刷新不会使操作系统多任务处理立即离开您的程序并切换到cat
程序。尝试在after 1000
和puts
命令之间放置gets
,你会发现你可能会收回字符串。然后给cat
一些时间片,并有机会读取它的输入并写出它的输出。
当 cat
读取您的输入并将其写回时,您无法控制,因此您必须使用fileevent
并输入事件循环以等待(或定期调用update
),或定期尝试从流中读取。或者您可以将其保持在阻止模式,在这种情况下gets
会等待您。它将阻塞,直到有一行要读取,但同时不会响应其他事件。例如,GUI将停止响应。
示例似乎是针对Tk并且意味着由wish
运行,piperead
在脚本结束时自动进入事件循环。添加wish
过程,然后使用vwait
运行脚本,或者在脚本末尾添加tclsh
命令,并使用grep
运行。
PS:对于用于管道的行缓冲I / O,所涉及的两个程序都必须使用它(或不使用缓冲)。许多程序(sed
,unbuffer
等)在未连接到终端时使用完全缓冲。阻止它们的一种方法是使用set pipe [open "|[list unbuffer grep .]" {RDWR}]
程序,它是Expect的一部分(您不必编写Expect脚本,它是一个独立的程序,恰好包含在Expect包中)。
{{1}}
答案 1 :(得分:1)
我猜您正在执行http://wiki.tcl.tk/3846的代码,该页面名为“Pipe vs Expect”。您似乎已经省略了piperead
proc的定义,实际上,当我从您的问题中复制并粘贴代码时,我收到了错误invalid command name "piperead"
。如果您从Wiki中复制并粘贴定义,您应该会发现代码有效。它确实对我有用。