【问题标题】:How to implement env | grep LANG with fork execve and pipe如何实现环境 |带有 fork execve 和管道的 grep LANG
【发布时间】:2020-08-11 17:19:57
【问题描述】:

我正在编写我的 minishell,但我不明白为什么调用 pid_2 时 execve 不起作用?
我的主要任务是实现 env | grep 朗


int main(void)
{
    pid_t pid_1, pid_2;
    int fd[2];
    int status;
    char *mass_1[] = {"env", NULL};
    char *mass_2[] = {"grep", "LANG", NULL};

    pid_1 = fork();
    pipe(fd);
    if (pid_1 == 0)
    {
        dup2(fd[1], 0);
        close(fd[0]);
        execve(mass_1[0], mass_1, NULL);
        exit(1);
    }
    pid_2 = fork();
    if (pid_2 == 0)
    {
        dup2(fd[0], 0);
        close(fd[1]);
        execve(mass_2[0], mass_2, NULL);
        exit(1);
    }
    close(fd[0]);
    close(fd[1]);
    waitpid(pid_1, &status, WUNTRACED);
    waitpid(pid_2, &status, WUNTRACED);
    return (0);
}

【问题讨论】:

  • dup2(fd[1], 0); dup2(fd[0], 0); 有问题,你是dup20 两次。他们中的一个不应该使用1 与标准输出连接吗?
  • pipe()fork() 之后也是错误的。这会在第一个子项中创建并使用一个单独的管道,而不是由父项创建的管道
  • env | grep LANG 还将打印值中包含 LANG 的变量。有更好的方法来做到这一点。见Get list of variables whose name matches a certain pattern
  • 无需 fork 和运行子进程即可访问您自己进程的环境变量。如果您在 POSIX 平台上,则可以通过 extern char **environ 变量直接访问整个环境变量列表。见pubs.opengroup.org/onlinepubs/9699919799/basedefs/…在Windows上,环境变量可以直接通过the GetEnvironmentStrings() function获得

标签: c


【解决方案1】:

您的代码中存在三个问题:

  1. execve() 不会在$PATH 中搜索命令,因此通常既找不到env 也找不到grep。请改用execvp()
  2. 您应该在第一个 fork() 之前调用 pipe() 以防止子进程创建和使用另一个管道
  3. 正如@KamilCuk 指出的那样:在第一个子进程中,您应该dup2()stdout 而不是stdin

修复这些错误会导致这个工作代码

#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <errno.h>

int main(void)
{
    pid_t pid_1, pid_2;
    int fd[2];
    int status;
    char *mass_1[] = {"env", NULL};
    char *mass_2[] = {"grep", "LANG", NULL};

    pipe(fd);
    pid_1 = fork();
    if (pid_1 == 0)
    {
        dup2(fd[1], 1);
        close(fd[0]);
        execvp(mass_1[0], mass_1);
        exit(1);
    }
    pid_2 = fork();
    if (pid_2 == 0)
    {
        dup2(fd[0], 0);
        close(fd[1]);
        execvp(mass_2[0], mass_2);
        exit(1);
    }
    close(fd[0]);
    close(fd[1]);
    waitpid(pid_1, &status, WUNTRACED);
    waitpid(pid_2, &status, WUNTRACED);
    return (0);
}

顺便说一句。您应该添加一些错误处理,例如pipe()fork() 可能会失败

如果您不能调用execvp(),则必须提供execve() 的路径名,例如"/usr/bin/env""/bin/grep"。在这种情况下,您还必须至少向env 提供父环境,否则它不会打印任何内容。 最简单的方法是:

  • main()的签名改为int main(int argc, char *argv[], char *envp[])
  • 致电execve(mass_1[0], mass_1, envp);

【讨论】:

  • 不幸的是,这段代码不适合我,因为我只需要使用 execve 但感谢您修复我的错误
  • 那你得自己找命令的路径名了
  • 如果我指定路径 /bin/env 和 /bin/grep 应该可以吗?它适用于 execvp,但它不适用于 execve,尽管我已经指定了命令的路径
  • 使用 execve() 确实会导致另一个问题。将 NULL 作为环境传递会导致 env 不知道任何变量,因此不打印任何内容。我正在进行另一次编辑
  • 我刚刚添加了 int main(int ac, char ** av, char **env) 并添加了 env 而不是 NULL
猜你喜欢
  • 2014-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-10
  • 1970-01-01
  • 2014-05-12
  • 2011-01-12
相关资源
最近更新 更多