【问题标题】:Why is execvp() executing twice using fork()?为什么 execvp() 使用 fork() 执行了两次?
【发布时间】:2016-06-15 01:49:51
【问题描述】:

我正在实现一个外壳。

当尝试更改目录以外的命令时,execvp() 运行,子进程终止并创建一个新子进程。当我更改目录时,孩子不会终止并创建一个新的孩子。这是我的代码示例:

for(;;) {
    printf("bash: ");
    parse();
    ...
    pid_t pid = fork()
    if (pid == 0)
        if (!strcmp(line[0], "cd"))
            if (!line[1]) (void) chdir(getenv("HOME"));
            else (void) chdir(line[1]);
        else execvp(line[0], line);
    ...
    if (pid > 0) {
        while (pid == wait(NULL));
        printf("%d terminated.\n", pid);
    }
}

cd ../; ls; 运行正常,但我必须Ctrl+D 两次才能结束程序。

但是,如果我通过管道传输相同的信息(即mybash < chdirtest),它会正确运行一次,终止子进程,然后直接在原始文件中再次运行,然后终止最后一个子进程。

【问题讨论】:

  • 当您运行cd 时,显示的(不完整)代码将不会调用execvp。相反,它将执行chdir,然后继续运行下一个for 循环迭代,该迭代将调用fork。这就是cd 情况下第一个子进程不退出的原因。
  • 欢迎来到 Stack Overflow。请尽快阅读About 页面。我的直接看法是,这里没有足够的信息让我们能够回答——魔鬼在细节中,而细节缺失。但是,@kaylum 至少解决了部分问题,并且可能已经确定了主要问题。 (我会观察到if (pid == 0) 之后的条件让我石化——没有足够的大括号,如果execvp() 或chdir() 失败,则没有错误处理。)请阅读如何创建 MCVE (minimal reproducible example) 和然后提供一个。
  • @kaylum 我不希望cd 调用execvp()。我希望它更改目录,循环返回,然后运行下一行而不出现问题。
  • 很好,但你的问题是为什么孩子不退出。这是试图解释原因。如果您认为该解释不正确,请指出原因。如果您不希望它再次分叉,那么cd 案例应该调用chdir,然后继续解析并执行下一个命令,而不需要另一个fork。
  • "创建一个 bash 程序" 不,你正在实现一个 shell(可能类似于 bash)

标签: c linux bash fork


【解决方案1】:

cd 不应通过子进程调用,shell 本身应更改其当前目录(这是内部命令的属性:修改 shell 本身的进程)。

一个(原始的)外壳应该是这样的:

for(;;) {
    printf("bash: ");
    parse();

    // realize internal commands (here "cd")
    if (!strcmp(line[0], "cd")) {
       if (!line[1]) (void) chdir(getenv("HOME"));
       else (void) chdir(line[1]);
       continue; // jump back to read another command
    }

    // realize external commands
    pid_t pid = fork()
    if (pid == 0) {
        execvp(line[0], line);
        exit(EXIT_FAILURE); // wrong exec
    }

    // synchro on child
    if (pid > 0) {
        while (pid == wait(NULL));
        printf("%d terminated.\n", pid);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-11
    • 1970-01-01
    • 2015-07-18
    • 2020-02-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多