尝试实现重定向。对文件描述符和dup2函数的理解有困难。

3

我需要实现一个带有重定向功能的shell,但是我在如何处理文件描述符方面遇到了麻烦。 在我的test.c文件中,我正在进行实验,尝试将'python --version'的输出导入到名为'out'的文件中。

int main(int argc, char *argv[], char *const envp[])
{
/***/TOKENIZER *tester;
    int pid = 0;
    int pipefd[2];
    char buffer = 0;

    pipe(pipefd); 
    pid = fork();
    pipefd[1] = open("out", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);

    if(pid == 0){
        close(pipefd[1]);
        dup2(pipefd[0], STDIN_FILENO); 
        close(pipefd[0]);
        while(read(STDIN_FILENO, &buffer, 1) > 0){
            write(STDOUT_FILENO, &buffer, 1);
        }

        close(pipefd[0]);
        _exit(EXIT_SUCCESS);
    }else{
        close(pipefd[0]);
        dup2(pipefd[1], STDOUT_FILENO); 
        close(pipefd[1]);

        write(STDOUT_FILENO, "asdsd\n", 6);

        char* ver[2];
        ver[1] = "--version";
        execvp("python", ver);
        exit(EXIT_SUCCESS);
    }
    free(tester);


    return 0;

编辑:我意识到自己混淆了重定向和管道的部分。以下是我试图运行的一些重定向代码。

int out = open("output.txt", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);

dup2(out, 1);
close(out);

char* ver[2];
ver[1] = "--version";
execvp("python", ver);
exit(EXIT_SUCCESS);

return 0;

我试图将Python版本信息输出到output.txt中,但似乎缺少某些东西,因此它无法正常工作。
编辑2:看起来它正在执行,但输出结果是标准输出而不是output.txt。
int out = open("output.txt", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);
dup2(out, STDOUT_FILENO);

char* ver[3];
ver[0] = "python";
ver[1] = "--version";
ver[2] = NULL;
execvp("python", ver);
perror("exec");

return 0;
1个回答

1
    int pid = 0;
    int pipefd[2];
    char buffer = 0;

    pipe(pipefd); 
    pid = fork();

目前为止,一切都很好。您已经创建了一个管道,其两个文件描述符存储在pipefd [0]pipefd [1]中,并创建了一个子进程。

    pipefd[1] = open("out", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);

哦,不!你刚刚用另一个文件描述符覆盖了一个完好无损的文件描述符(管道的写端),让它指向名为“out”的普通文件。

你是想进行常规文件重定向还是管道?在尝试实现shell之前,至少应该知道这两个是不同的东西。如果你想模仿python --version > out,那么你应该注意到该命令行中没有管道字符,所以为什么会想象有管道参与实现呢?

此外,由于你在fork之后执行了这个操作,所以现在两个进程都在运行,两者都会打开文件,包括创建和截断的副作用。这肯定不是你想要的。

我会在此停下,因为在你解决这一部分之前,程序的其余部分都没有意义。

但是还有一些随机的笔记:

  • 3个参数的main函数已经过时了。使用getenv()environ来查找环境变量。
  • 单字节缓冲区不够高效,使用更大的缓冲区也不会更难。
  • 在父进程中执行exec而不是在子进程中执行,这很奇怪 - 不一定是致命问题,但绝对不寻常。

啊,你说得对。看来我混淆了<和|的元素。这就是我同时研究它们的后果,哈哈。是的,envp是上个月当我必须使用execve而不是execvp时遗留下来的。我可能可以删除那个。谢谢!我会研究你的答案! - Saxophlutist
无论如何,我刚刚添加了一些简单的重定向代码,但它没有起作用,所以我觉得我没有正确理解dup2()。 - Saxophlutist
1
在尝试执行操作之前,您需要在ver [0]中放置一些内容。即使Python不关心其argv [0],内核也需要指向合法字符串的指针,否则执行将失败。在执行后,您应该打印错误消息(即perror(“ exec”);)而不是EXIT_SUCCESS,因为除非出现错误,否则exec永远不会返回。您的其他系统调用也需要进行一些错误检查... - user2404501
当然,你需要在ver的末尾放置一个NULL,因此将其设置为3个元素长,并设置ver[2]=NULL - user2404501
啊,好的。看起来它又开始执行了。不过似乎它还是将输出发送到标准输出流。 (代码已上载) - Saxophlutist
1
恭喜你。你已经成功模仿了 python --version > output.txt 命令。现在可以尝试在你的 shell 提示符下执行该命令。Python 会将版本号发送到 stderr - user2404501

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接