模拟 execvp - 有更好的方法吗?

发布于 2024-11-18 03:58:49 字数 1391 浏览 4 评论 0原文

我目前正在用 Tcl/Tk 包装一个命令行工具(espeak),到目前为止我已经弄清楚了:

load ./extensions/system.so
package require Tk
package require Tclx

set chid 0

proc kill {id} {
    exec kill -9 $id
}

proc speak {} {
    global chid
    set chid [fork]
    if {$chid == 0} {
        execvp espeak [.text get 1.0 end]
    }
}

proc silent {} {
    global chid
    kill $chid
}

其中 system.so 是我一起破解的扩展,以便能够使用 execvp

#include <tcl.h>
#include <tclExtend.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

static int 
execvp_command(ClientData cdata, Tcl_Interp *interp, int argc, const char* argv[])
{   
    if (argc == 1)
    {
        interp->result = "execvp command ?args ...?";
        return TCL_ERROR;
    }

    execvp(argv[1], argv + 1);

    return TCL_OK;
}

int System_Init(Tcl_Interp* interp)
{
    if (Tcl_InitStubs(interp, "8.1", 0) == NULL)
        return TCL_ERROR;

    Tcl_CreateCommand(interp, "execvp", execvp_command, NULL, NULL);

    Tcl_PkgProvide(interp, "system", "1.0");

    return TCL_OK;
}

我需要 execvp 的原因是因为由 exec (Tcl) 创建的子进程似乎在进程终止时继续运行(我可以通过以下方式确认这一点) ^C'ing out of the GUI),而如果我使用 execvpespeak 会正常终止。

因此,我从这个脚本中真正需要的是能够启动一个子进程并根据需要终止它。

是否有另一个库可以正确执行此操作,例如 Expect?

I'm currently wrapping a command line tool (espeak) with Tcl/Tk, and I have figured this out so far:

load ./extensions/system.so
package require Tk
package require Tclx

set chid 0

proc kill {id} {
    exec kill -9 $id
}

proc speak {} {
    global chid
    set chid [fork]
    if {$chid == 0} {
        execvp espeak [.text get 1.0 end]
    }
}

proc silent {} {
    global chid
    kill $chid
}

Where system.so is an extension I hacked together to be able to use execvp:

#include <tcl.h>
#include <tclExtend.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

static int 
execvp_command(ClientData cdata, Tcl_Interp *interp, int argc, const char* argv[])
{   
    if (argc == 1)
    {
        interp->result = "execvp command ?args ...?";
        return TCL_ERROR;
    }

    execvp(argv[1], argv + 1);

    return TCL_OK;
}

int System_Init(Tcl_Interp* interp)
{
    if (Tcl_InitStubs(interp, "8.1", 0) == NULL)
        return TCL_ERROR;

    Tcl_CreateCommand(interp, "execvp", execvp_command, NULL, NULL);

    Tcl_PkgProvide(interp, "system", "1.0");

    return TCL_OK;
}

The reason I need execvp is because a subprocess created by exec (Tcl) seems to keep going when the process dies (I can confirm this by ^C'ing out of the GUI), whereas if I use execvp, espeak dies properly.

Thus, all I really need out of this script is to be able to start a subprocess and kill it on demand.

Is there another library that can do this properly, like Expect?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

隱形的亼 2024-11-25 03:58:49

Tcl 在内部使用 execvp (确实;我刚刚检查了源代码),因此差异在于其他地方。其他地方将出现在信号中;由 exec 命令创建的子进程(以及使用相同底层引擎的其他事物)将强制大多数信号使用默认信号处理程序,但由于它设置为非默认信号的唯一信号是 SIGPIPE,我想知道还发生了什么。

也就是说,处理此类事情的最终扩展是 TclX。这使您可以访问您一直在部分使用的所有低级 POSIX 功能。 (期望也能做到。)

Tcl uses execvp internally (really; I've just checked the source) so the difference lies elsewhere. That elsewhere will be in signals; the subprocess created by the exec command (and other things that use the same underlying engine) will have the majority of signals forced to use the default signal handlers, but since the only signal it sets to non-default is SIGPIPE, I wonder what else is going on.

That said, the definitive extension for working with this sort of thing is TclX. That gives you access to all the low-level POSIX functionality that you've been using partially. (Expect may also be able to do it.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文