Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在c中管理shell的管道端点_C_Shell - Fatal编程技术网

如何在c中管理shell的管道端点

如何在c中管理shell的管道端点,c,shell,C,Shell,我正在尝试制作一个支持管道的c型外壳。到目前为止,它一直工作,直到我尝试一个涉及一个大文件的命令,在这种情况下,它失败了。我认为这是因为我无法处理超过一根管道的数据量 static int execute(Sequence* sequence) { pid_t pid; pid = fork(); if (pid == 0) { /* child process */ execvp(sequence->args[0], sequence->args);

我正在尝试制作一个支持管道的c型外壳。到目前为止,它一直工作,直到我尝试一个涉及一个大文件的命令,在这种情况下,它失败了。我认为这是因为我无法处理超过一根管道的数据量

static int execute(Sequence* sequence) {
   pid_t pid;

   pid = fork();
   if (pid == 0) { /* child process */
      execvp(sequence->args[0], sequence->args);
   }
   else if (pid < 0) {
      perror("execute");
   }

   return pid;
}

int runCommands(Sequence* sequences, int seqSize) {
   /* sets up pipes for all processes but the last */
   for (i = 0; i < seqSize-1; i++) {
      /* pipe, store fds and execute */
   }

   /* execute last */

   /* wait for pids */

   return 0;
}
我在main中使用正确的序列数组调用runCommands。在测试时,我发现当我使用类似“catlarge_file | head-10”的东西运行它时,head会终止,但cat不会


我是否没有正确关闭文件描述符?

这是正常问题-您没有关闭足够多的文件描述符

如果您有一个三阶段管道,那么在开始分叉之前,在父进程中打开两个管道或四个描述符,再加上原始的标准输入和标准输出。当第一个子对象分叉时,它关闭4个管道描述符中的1个,即连接到其标准输出的管道描述符。它使其他3个打开,这是一场灾难。第二个子项关闭4个管道描述符中的2个,但保留其他2个打开。第三个子项关闭4个管道描述符中的1个。而且,父进程仍然打开所有文件描述符;在进行任何等待之前,它还需要关闭所有管道描述符

由于第一个管道的写入端在最后一个进程中仍然打开,第二个进程在其标准输入上没有获得EOF,因此代码挂起,第二个进程等待永远不会到达的输入

即使是在一个简单的两阶段管道中,您也会遇到这样的问题:父进程打开了管道的写入端。(我认为第二个子级也打开了管道的写入端,但父级足以挂起代码。)

你必须关闭更多的文件描述符

您可以查看和,以了解经验法则的两个小变化:

  • 经验法则:如果将管道的一端复制到流程的标准输入或标准输出,则需要在该流程中关闭管道的两端

在SO上搜索“user:15168[c]rule thumb pipe”会找到10个其他答案,其中这条信息是作为经验法则呈现的。当然,你需要知道这是一个很好的搜索;你不会知道那是先验的。

…还是*?我们必须至少每周以某种形式问一次这个问题。你是否尝试过搜索以前的实例(及其答案)?@Charles Duffy是的,我尝试过。其中一个是我的,你评论过了,但我被一位同行告知这不是一个足够好的问题,所以我删除了它。希望这个改写的更好。谢谢你的回复。因此,如果我理解您的意思,每次我分叉时,在我的孩子中,我应该在执行之前关闭所有文件描述符?每个孩子都应该关闭所有管道文件描述符(根据需要复制到标准输入和/或标准输出后)。父级还需要关闭所有管道文件描述符。另外,如果您很勇敢的话,POSIX规范说明,如果您尝试将文件描述符N复制到自身,那么不会出现任何问题,因此您可以简单地进行复制,而无需测试标准输入和标准输出。这是否真的是一个好主意更值得商榷,但即使是POSIX1990也需要它。
typedef struct
{
    int read;
    int write;
    char* arg[MAX_ARGS+1];
} Sequence;