当前位置: 首页 > 面试题库 >

在C中实现Shell并需要帮助来处理输入/输出重定向

姜森
2023-03-14
问题内容

第二回合

阅读了一些答案后,我的修改代码是:

int pid = fork();

if (pid == -1) {
    perror("fork");
} else if (pid == 0) {

    if (in) { //if '<' char was found in string inputted by user
        int fd0 = open(input, O_RDONLY, 0);
        dup2(fd0, STDIN_FILENO);
        close(fd0);
        in = 0;
    }

    if (out) { //if '>' was found in string inputted by user
        int fd1 = creat(output, 0644);
        dup2(fd1, STDOUT_FILENO);
        close(fd1);
        out = 0;
    }

    execvp(res[0], res);
    perror("execvp");
    _exit(1);
} else {
    waitpid(pid, 0, 0);
    free(res);
}

它可以工作,但是似乎标准输出没有被重新连接或达到某种效果。这是执行:

SHELL$ cat > file
hello, world
this is a test
SHELL$ cat < file //no output
SHELL$ ls //no output

’<’和’>’都可以,但是执行后就没有输出。

第1轮

我已经在C语言中使用相对简单的shell了一段时间,但是在实现输入(<)和输出(>)重定向时遇到了麻烦。帮我找到以下代码中的问题:

int fd;
int pid = fork();
int current_out;

if (in) { //if '<' char was found in string inputted by user
    fd = open(input, O_RDONLY, 0);
    dup2(fd, STDIN_FILENO);
    in = 0;
    current_out = dup(0);
}

if (out) { //if '>' was found in string inputted by user
    fd = creat(output, 0644);
    dup2(fd, STDOUT_FILENO);
    out = 0;
    current_out = dup(1);
}

if (pid == -1) {
    perror("fork");
} else if (pid == 0) {       
    execvp(res[0], res);
    perror("execvp");
    _exit(1);
} else {
    waitpid(pid, 0, 0);
    dup2(current_out, 1);
    free(res);
}

我可能那里有一些不必要的材料,因为我一直在尝试不同的方法来使其正常工作。我不确定出了什么问题。


问题答案:

重定向后,打开的文件描述符太多了。让我们剖析两段:

if (in) { //if '<' char was found in string inputted by user
    fd = open(input, O_RDONLY, 0);
    dup2(fd, STDIN_FILENO);
    in = 0;
    current_in = dup(0);  // Fix for symmetry with second paragraph
}

if (out) { //if '>' was found in string inputted by user
    fd = creat(output, 0644);
    dup2(fd, STDOUT_FILENO);
    out = 0;
    current_out = dup(1);
}

我将慈善起来,忽略您忽略错误的事实。但是,您将需要错误检查系统调用。

在第一段中,打开文件并在变量中捕获文件描述符(很可能是3)fd。然后,您可以在标准输入(STDIN_FILENO)上复制文件描述符。但是请注意,文件描述符3仍处于打开状态。然后,执行一个dup(0)(为了保持一致,应该为STDIN_FILENO),得到另一个文件描述符,也许是4。因此,文件描述符0、3和4指向相同的文件(实际上是相同的打开文件描述,请注意)打开文件描述与打开文件描述符不同)。如果您打算current_in保留(父)外壳的标准输入,则必须先执行此操作,dup()然后再执行dup2()覆盖输出。但是,最好不要更改父Shell的文件描述符。它比重新复制文件描述符要少。

然后,您或多或少重复第二段中的过程,首先覆盖通过fd = creat(...)调用打开的文件描述符3的唯一记录,但获得一个新的描述符(可能是5),然后在标准输出中复制该描述符。然后执行dup(1),产生另一个文件描述符,也许是6。

因此,您已经将主外壳程序的stdin和stdout重定向到了文件(并且没有将它们恢复为原始值的方法)。因此,您的第一个问题是您要先进行重定向fork();您应该在之后执行该操作fork()-尽管在流程之间进行管道传输时,需要在创建分支之前创建管道。

第二个问题是,您需要关闭过多的文件描述符,而其中的一个文件描述符将不再具有引用。

因此,您可能需要:

if ((pid = fork()) < 0)
    ...error...
else if (pid == 0)
{
    /* Be childish */
    if (in)
    {
        int fd0 = open(input, O_RDONLY);
        dup2(fd0, STDIN_FILENO);
        close(fd0);
    }

    if (out)
    {
        int fd1 = creat(output , 0644) ;
        dup2(fd1, STDOUT_FILENO);
        close(fd1);
    }
    ...now the child has stdin coming from the input file, 
    ...stdout going to the output file, and no extra files open.
    ...it is safe to execute the command to be executed.
    execve(cmd[0], cmd, env);   // Or your preferred alternative
    fprintf(stderr, "Failed to exec %s\n", cmd[0]);
    exit(1);
}
else
{
    /* Be parental */
    ...wait for child to die, etc...
}

在执行任何此操作之前,您应该确保已使用刷新了Shell的标准I /
O通道fflush(0),这样,如果派生的子级由于问题而写入标准错误,则不会有多余的重复输出。

还要注意,open()应该对各种调用进行错误检查。



 类似资料:
  • 问题内容: 我正在尝试使用C为Linux创建一个基本的shell。在我尝试进行输出重定向之前,它已经可以工作了,并且它破坏了一切。当我运行此代码时,它直接进入fork()的默认情况。我不知道为什么。如果我在子进程中摆脱了for循环,那么它就可以工作,但是即使有了for循环,我也不明白为什么子进程甚至从未输入。如果将打印语句放在子进程的顶部,则不会打印出来。 当我在命令行中运行此命令时,我得到提示并

  • 1. Shell 重定向 1.1 Shell 重定向是什么 我们在之前章节有学习 echo/printf 来将我们的需求输出,此时就是我们将系统的返回输出到我们标准终端,使得我们能够看到正常的输出的结果,Unix 命令默认的输入设备即 stdin 为键盘,标准和错误设备即 stdout 为显示器,我们利用重定向可以将输入改为文件,或者将输出重新定向到其他设备或文件中。 1.2 为什么要用重定向 我

  •   大多数 UNIX 系统命令从你的终端接受输入并将所产生的输出发送回​​到您的终端。一个命令通常从一个叫标准输入的地方读取输入,默认情况下,这恰好是你的终端。同样,一个命令通常将其输出写入到标准输出,默认情况下,这也是你的终端。 命令 说明 command > file 将输出重定向到 file。 command < file 将输入重定向到 file。 command >> file 将输出以

  • 我想深入了解Jmeter输出。 > 我对吞吐量率的概念感到困惑。这是否意味着服务器在给定负载下只能处理48.1个请求/分钟,还是意味着其他什么。总吞吐量速率和单个请求显示的吞吐量速率之间的差异是什么。在我的情况下,发送了8个请求,单个请求显示吞吐量为6.1/min。请解释一下。 我需要建议服务器端的任何更改/解释jmeter报告,请建议我如何解释需要做什么。 总的总结报告如下: 总用户: 100上

  • 问题内容: 我有一个UNIX本机可执行文件,它要求像这样输入参数 prog.exe <foo.txt。 foo.txt有两行:bar baz 我正在使用java.lang.ProcessBuilder来执行此命令。不幸的是,prog.exe仅能使用文件重定向功能。有什么办法可以模仿Java中的这种行为? 当然, 不起作用。 谢谢! 问题答案: 未经测试,但类似的东西应该起作用。