关于如何结束 Execvp 调用的困惑

Confusion Regarding How to Wrap an Execvp Call

我无法获得使用 execvp 调用的程序的完整输出。在这里,我基本上是想用一个可以过滤输入和输出的程序来包装任何程序:

#define BUF_SIZ 8192
int main(int argc, char **argv) {
    int outp[2]; // r, w
    int inp[2];
    pid_t pid;
    char buf[BUF_SIZ];
    fd_set fds;
    struct timeval tv;

    tv.tv_sec = 0;
    tv.tv_usec = 300000;
    if (pipe(outp) < 0 || pipe(inp) < 0) return 1;
    if ((pid = fork()) < 0) return 2;
    else if (pid) {
        close(outp[1]);
        close(inp[0]);
        dup2(outp[0], STDIN_FILENO);
        dup2(inp[1], STDOUT_FILENO);
        execvp(*(argv + 1), argv + 1);
    } else {
        while (1) {
            FD_ZERO(&fds);
            FD_SET(STDIN_FILENO, &fds);
            FD_SET(inp[0], &fds);
            if (select(inp[0] + 1, &fds, NULL, NULL, &tv) < 0) exit(3);
            if (FD_ISSET(STDIN_FILENO, &fds))
                write(outp[1], buf, read(STDIN_FILENO, buf, BUF_SIZ));
            if (FD_ISSET(inp[0], &fds))
                write(STDOUT_FILENO, buf, read(inp[0], buf, BUF_SIZ));
        }
    }

    return 0;
}

如果我使用程序调用 shell sh,我得到以下输出(我没有收到提示):

$ ./shell sh    
echo "test"
test
^C

如果我尝试 运行 Python;我没有收到输出:

$ ./shell python
print "test"
^C

为什么我没有收到(大部分)输出?

问题是,您的 shell 和 python 解释器的标准输入不是终端。在这种情况下,两个程序的行为有点不同:

  • shell不发出提示
  • Python 想先从标准输入(直到 EOF)读取它的完整脚本

例如,要使 python 脚本正常工作,您必须从 您的 标准输入(读取 returns 0)捕获 EOF,在这种情况下关闭 python 进程的标准输入。然后,您可以通过在终端上按 CTRL+D 来调用 EOF。

if (select(inp[0] + 1, &fds, NULL, NULL, &tv) < 0) exit(3);
if (FD_ISSET(STDIN_FILENO, &fds)) {
    int st = read(STDIN_FILENO, buf, BUF_SIZ));
    if (st > 0)
        write(outp[1], buf, st);
    else {
        close(outp[1]);
    ...

如果您想拥有一个交互式终端,您将不得不打开一个新的伪终端,forkpty(3) 将为您完成大部分工作。