Tcl期望“交互”命令回应生成的rlwrap进程的先前输出

时间:2013-10-10 08:40:12

标签: tcl expect

我感觉有一些显而易见的东西我不见了,但到目前为止,我的搜索工作还没有结果。

我正在尝试使用tcl / expect脚本来启动tclsh交互式shell,添加一个程序,以便轻松地重新加载实用程序以进行测试,然后将正常控制返回给我。

到目前为止,我发现使tcl交互式shell“可用”的一种方法是使用“rlwrap”启动它,以便我可以使用箭头键等。

所以我尝试了下面的脚本,有关rlwrap的一些内容导致以前的输出在命中interact命令时被转储到stdout。

我能做些什么才能避免这种情况发生?

代码:

package require Expect


puts "Tcl version   : [info tclversion]"
puts "Expect version: [exp_version]"


log_user 0
spawn -noecho rlwrap tclsh

# Create procedure to easily reload utilites after changes have been made
expect "% "
send {
   proc reload {} {
      # Procedure to reload utility source easily for testing
   }
}

# Source utilities
expect "% "
send "reload\r"

send_user "\nUse 'reload' procedure to re-source utility files\n\n"

log_user 1
interact

输出:

Tcl version   : 8.4
Expect version: 5.43.0

Use 'reload' procedure to re-source utility files


   proc reload {} {
      # Procedure to reload utility source easily for testing
   }
% reload
%  

由于某种原因,你可以回应proc定义和输入reload命令。一旦发生交互,就会发生这种情况。如果我用“退出”替换交互,我看不到任何输出。

当然,我希望看到的输出是这样的:

Tcl version   : 8.4
Expect version: 5.43.0

Use 'reload' procedure to re-source utility files

%  

2 个答案:

答案 0 :(得分:1)

如果您不介意自己编译一个小型C程序,可以使用它:

#include <tcl.h>

#ifdef WIN32
#ifdef UNICODE
#define WIN32_UNICODE
#endif
#endif

int TclSHI_Main(Tcl_Interp*);

static int g_argc;
#ifdef WIN32_UNICODE
#define Tcl_NewStringObj Tcl_NewUnicodeObj
static wchar_t*** g_argv;
void wmain(int argc, wchar_t **argv) {
#else
static char*** g_argv;
void main(int argc, char **argv) {
#endif
    g_argc = argc;
    g_argv = &argv;
    Tcl_FindExecutable(argv[0]);
    Tcl_Main(1, argv, TclSHI_Main);
}

int TclSHI_Main(Tcl_Interp* interp) {
    Tcl_Obj* lobj;
    int i;
    if (g_argc > 1) {
        Tcl_SetVar2Ex(interp, "argv0", NULL, Tcl_NewStringObj((*g_argv)[1], -1), TCL_GLOBAL_ONLY);
    }
    lobj = Tcl_NewObj();
    Tcl_IncrRefCount(lobj);
    for (i = 2; i < g_argc; i++) {
        Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj((*g_argv)[i], -1));
    }
    Tcl_SetVar2Ex(interp, "argv", NULL, lobj, TCL_GLOBAL_ONLY);
    Tcl_DecrRefCount(lobj);
    Tcl_SetVar2Ex(interp, "argc", NULL, Tcl_NewIntObj(g_argc - 2), TCL_GLOBAL_ONLY);
    if (g_argc > 1) {
        Tcl_Eval(interp, "source $argv0");
    }
    return TCL_OK;
}

我在windows(CL)和linux(GCC)上测试过它 要使用gcc编译它,我使用了gcc TclSH.c -o TclSHI -ltcl8.6
在Windows上我使用Visual Studio。

它告诉Tcl它没有收到任何参数(Tcl_Main(1,...)),但用这个参数填充新的interp并获取文件。在这一步之后,它将始终显示提示(它从未收到任何参数,对吧?)。

您的期望解决方案存在一个小问题,如果您指定任何参数,Tcl将执行该脚本,并且从不显示提示。

另请注意,我是新手C程序员,所以此解决方案可能不是防弹。

答案 1 :(得分:0)

您要做的是等待明确的标记,表明从属流程已准备就绪。

# ... your script as above ...
expect "% "

#### NEW STUFF STARTS ####
send "reload;puts READY\r"
expect "READY\r"

# Note that we need to fake the prompt; c'est la vie
send_user "\nUse 'reload' procedure to re-source utility files\n\n% "

# Now start doing things!
log_user 1
interact

或者至少当我尝试使用从属进程时,这是有效的,但我没有在混合中使用rlwrap,这可能会改变一些事情......