1

虽然我对 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"
4

2 回答 2

2

写入管道和刷新不会使操作系统多任务立即离开您的程序并切换到cat程序。尝试在命令和命令after 1000之间放置,你会发现你可能会得到字符串。然后被赋予了一些时间片,并且有机会读取它的输入并写入它的输出。putsgetscat

您无法控制何时 cat读取输入并将其写回,因此您必须使用fileevent并进入事件循环以等待(或定期调用update),或定期尝试从流中读取。或者您可以将其保持在阻塞模式,在这种情况下gets会等待您。它将阻塞直到有一行要读取,但同时不会响应其他事件。例如,GUI 将停止响应。

该示例似乎是针对 Tk 的,旨在由 运行wish,它在脚本末尾自动进入事件循环。添加piperead过程并使用 运行脚本wish或在脚本末尾添加vwait命令并使用tclsh.

PS:要让行缓冲 I/O 为管道工作,所涉及的两个程序都必须使用它(或不使用缓冲)。许多程序(grep,sed等)在未连接到终端时使用完全缓冲。防止它们发生的一种方法是使用unbuffer程序,它是 Expect 的一部分(您不必编写 Expect 脚本,它是一个独立的程序,恰好包含在 Expect 包中)。

set pipe [open "|[list unbuffer grep .]" {RDWR}]
于 2013-04-26T23:12:35.157 回答
1

我猜您正在执行来自http://wiki.tcl.tk/3846的代码,该页面标题为“Pipe vs Expect”。您似乎省略了pipereadproc 的定义,实际上,当我从您的问题中复制并粘贴代码时,我得到了一个错误invalid command name "piperead"。如果您从 wiki 复制并粘贴定义,您应该会发现代码有效。它确实对我有用。

于 2013-04-26T23:01:46.320 回答