Tcl/Expect脚本由名称管道块/缓冲区驱动意外输出

Tcl/Expect脚本由名称管道块/缓冲区驱动意外输出,tcl,expect,Tcl,Expect,我正在尝试编写一个expect脚本,该脚本对读取管道的输入作出反应。在文件“CuloLo.SH”中考虑这个例子: 现在,从另一个终端尝试: export CMDPIPE=~/.cmdpipe echo ls >> ${CMDPIPE} echo pwd >> ${CMDPIPE} 在第一个终端中,只要在每个echo命令上按enter键,就会立即打印“get command:ls/pwd”行,但是生成的bash shell没有输出(没有文件列表和当前目录)。现在,再试一次

我正在尝试编写一个expect脚本,该脚本对读取管道的输入作出反应。在文件“CuloLo.SH”中考虑这个例子:

现在,从另一个终端尝试:

export CMDPIPE=~/.cmdpipe
echo ls >> ${CMDPIPE}
echo pwd >> ${CMDPIPE}
在第一个终端中,只要在每个echo命令上按enter键,就会立即打印“get command:ls/pwd”行,但是生成的bash shell没有输出(没有文件列表和当前目录)。现在,再试一次:

echo ls >> ${CMDPIPE}
前两个命令的输出突然出现,但第三个命令(第二个ls)不可见。继续,您将注意到显示的输出中有一个“滞后”,它似乎被“缓冲”,然后立即转储

为什么会发生这种情况?我如何修复它?

根据:

通常,打开FIFO块,直到另一端也打开

因此,在proc
read_命令中,它阻塞了
set cpipe[open“$::env(CMDPIPE)”r]
,并且在
echo…>>${CMDPIPE}
再次

要解决此问题,可以在非阻塞模式下打开FIFO(命名管道):

set cpipe [open "$::env(CMDPIPE)" {RDONLY NONBLOCK} ]
以下章节也提到了这一点:

进程可以在非阻塞模式下打开FIFO。在这种情况下,即使还没有人在写端打开,为只读打开也会成功

下面是代码的简化版本,对我来说很好(在Debian 9.6上测试)

spawn bash--norc
设置超时-1
expect-re{bash-[.0-9]+[#$]$}
发送“PS1='P'rompt:'\r”
#         ^^^^
预期“提示”:
proc do{cmd}{
发送“$cmd\r”
如果{$cmd==“退出”}{
预期eof
出口
}否则{
预期“提示”:
}
}
proc read_命令{}{
全球cpipe
如果{[gets$cpipe cmd]<0}{
收盘价$cpipe
设置cpipe[打开cpipe{RDONLY NONBLOCK}]
fileevent$cpipe readable read_命令
}否则{
做$cmd吗
}
}
设置cpipe[打开cpipe{RDONLY NONBLOCK}]
fileevent$cpipe readable read_命令
永远等待

我尝试了你的建议,但不幸的是,行为还是一样。请注意,我已经用“fconfigure$cpipe-blocking 0”设置了非阻塞模式。即使您打开管道的方式没有任何变化。我应该补充一点,如果您将示例复制粘贴到两个bash终端中,您将看到在运行echo发送命令后立即调用[put“get command:$cmd”]语句。因此,阅读准备似乎很好。它只是缺少实际命令的输出。在我看来,这似乎是一个缓冲问题,或者与Tcl中的事件循环和/或我不知道的预期(对Tcl了解不多)有关。我自己尝试过,效果很好。它是
open
阻止的,所以
fconfigure-blocking 0
在这里没有帮助。这是修复它的更改:发送“PS1='P''rompt:'\r“仅供参考,我在Ubuntu上看到了与您相同的行为。更新基于1.7的Cygwin在我的Windows机箱上复制了相同的内容。事实上,有两个问题,你都解决了。
echo ls >> ${CMDPIPE}
set cpipe [open "$::env(CMDPIPE)" {RDONLY NONBLOCK} ]
spawn bash --norc
set timeout -1

expect -re {bash-[.0-9]+[#$] $}
send "PS1='P''rompt: '\r"
#         ^^^^
expect "Prompt: "

proc do { cmd } {
    send "$cmd\r"
    if { $cmd == "exit" } {
        expect eof
        exit
    } else {
        expect "Prompt: "
    }
}

proc read_command {} {
    global cpipe
    if {[gets $cpipe cmd] < 0} {
        close $cpipe
        set cpipe [open cpipe {RDONLY NONBLOCK} ]
        fileevent $cpipe readable read_command
    } else {
        do $cmd
    }
}

set cpipe [open cpipe {RDONLY NONBLOCK} ]
fileevent $cpipe readable read_command
vwait forever