【问题标题】:Why my program terminates (using pipes)?为什么我的程序终止(使用管道)?
【发布时间】:2015-11-22 21:26:14
【问题描述】:

我想做一个可以使用管道的外壳。当我使用此代码在我的 shell 中运行管道时,即使所有内容都在 WHILE(1) 循环中,我的 shell 也会终止。为什么? dup函数使用有问题吗?

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
int main(void)
{


  int pfds[2];
  pipe(pfds);
  char *ar1;
  const char sp = ' ';
  int temp, temp1, temp2, acc;
  int i, j;
  int t = 0;
  char *line=(char *) malloc(1024*sizeof(char));
  char *frsarg=(char *) malloc(1024*sizeof(char));
  char *firstcmd=(char *) malloc(1024*sizeof(char));
  char *seccmd=(char *) malloc(1024*sizeof(char));
  char *scmd=(char *) malloc(1024*sizeof(char));
  char *secondcmd=(char *) malloc(1024*sizeof(char));
  char *secarg=(char *) malloc(1024*sizeof(char));
  char *frscmd=(char *) malloc(1024*sizeof(char));
  char *cmd1=(char *) malloc(1024*sizeof(char));
  char *cmd=(char *) malloc(1024*sizeof(char));
  char *cmdf=(char *) malloc(1024*sizeof(char));
  char *arg1=(char *) malloc(1024*sizeof(char));
  char *allarg=(char *) malloc(1024*sizeof(char));
  char *arg2=(char *) malloc(1024*sizeof(char)); 
  char *arg3=(char *) malloc(1024*sizeof(char));
while (1) {
       /* Ektypwse to command prompt */
       printf("$ ");
       fflush(stdout);                            



       fgets(line, 1024, stdin);                  //Reads the command.


       for(i=0;i<1024;i++){

           if(line[i]=='\n')                      //Deletes the "Enter" from the end of the string.
             {
               line[i]='\0';                      //Replace "Enter" with \0.

             }
          if(line[i] == 'e' && line[i+1] == 'x' && line[i+2] == 'i' && line[i+3] == 't' ) {
           exit(1);
          }


        }

   seccmd = strchr(line, '|'); 
   acc = 0;
    for(i=0;i<1024;i++){ 
       if(line[i]=='|'){
         acc = i;   
         t=t+1; 
        }                    //Finds the second space.
    }





/*FIRST COMMAND AND ARGUMENT*/

if(acc != 0 ){
       //printf("OKIF\n");                         
       for(j=0;j<acc;j++){
          //printf("OKFOR\n");                     
          frscmd[j]= line[j];                         
       }
      //printf("FIRST COMMAND %s\n", frscmd);                  
    }
 /*FIRST ARG*/
 frsarg = strchr(frscmd, sp);
    if(frsarg != NULL){
          while(isspace(*frsarg)) ++frsarg;                
    }

    for (i=0;i<1024;i++){
        if (frsarg[i] == ' '){
        frsarg[i] = '\0';
        }
    }


 /*FIRST COMMAND*/


 acc = 0;
 for(i=0;i<1024;i++){ 
       if(frscmd[i]==' '){
         acc = i;   
         break;
        }  

  }

 if(acc != 0 ){
       //printf("OKIF\n");                         
       for(j=0;j<acc;j++){
          //printf("OKFOR\n");                     
          firstcmd[j]= frscmd[j];                         
       }

 }
 if(firstcmd != NULL){
       while(isspace(*firstcmd)) ++firstcmd;  
 }
 printf("FIRST COMMAND TEST %s TEST\n", firstcmd);  
 printf("FIRST ARGUMENT TEST %s TEST\n", frsarg);

// firstcmd == "ls" ,frsarg == "-l"

/*SECOND COMMAND AND ARGUMENTS */

//seccmd = " | ws -l



//SECOND COMMAND WITHOUT "|" secondcmd = _wc_-l


secondcmd = strchr(seccmd, sp);
    if(secondcmd != NULL){
          while(isspace(*secondcmd)) ++secondcmd;                
    }



//SECCOND COMMAND scmd


 acc = 0;
 for(i=0;i<1024;i++){ 
       if(secondcmd[i]==' '){
         acc = i+1;   

        }  

  }

 if(acc != 0 ){

       for(j=0;j<acc;j++){

          scmd[j]= secondcmd[j];                         
       }

 }

for (i=0;i<1024;i++){
        if (scmd[i] == ' '){
        scmd[i] = '\0';
        }
    }

 printf("SECOND COMMAND TEST %s TEST\n", scmd);  

//SECOND ARGUMENT secarg


secarg = strchr(secondcmd, sp);
if(secarg != NULL){
          while(isspace(*secarg)) ++secarg;                
    }


printf("SECOND ARGUMENT TEST %s TEST\n", secarg);  


//FIRST COMMAND = firstcmd____FIRST ARGUMENT = frsarg_____SECOND COMMAND = scmd_____SECOND ARGUMENT = secarg

if (!fork()) {
        close(1);       /* close normal stdout */
        dup(pfds[1]);   /* make stdout same as pfds[1] */
        close(pfds[0]); /* we don't need this */
        execlp(firstcmd, firstcmd, frsarg,(char*) NULL);
    } else {
        close(0);       /* close normal stdin */
        dup(pfds[0]);   /* make stdin same as pfds[0] */
        close(pfds[1]); /* we don't need this */
        execlp(scmd, scmd, secarg,(char*) NULL);
    }

   return 0;


}
}

【问题讨论】:

  • 请编辑以显示调用此程序的工作 shell 脚本。
  • 您的基本 pipe/fork/exec 代码似乎没问题。在那些exec 电话之后会发生什么,谁都猜不透。该代码存在多个潜在问题,超出了 Unix 和 Linux 堆栈交换站点的范围。
  • 你的 shell 执行了一个 fork,然后父子进程都执行了 execlp。这将用 scmd 替换 shell,并且该 while 循环将不复存在。 shell 通常会让 fork 的父进程执行 waitpid,而不是 exec。
  • @MarkPlotnick 你能告诉我我必须做的改变吗?我对软件编码非常陌生,所以在我能够解决像这样的问题之前,我必须了解它们的工作原理。提前谢谢你。
  • 了解如何调试。对程序的哪一部分失败进行有根据的猜测;然后删除不相关的部分并重新测试。重复。如果问题消失了,您刚刚删除的代码可能(至少部分)负责。如果你达到了不能再切割的地步,那么你已经缩小了问题的范围。最后,当您将最小示例代码发布到 Stack Exchange 时,正确缩进!  P.S.如果你认为你正在编写一个 shell,不要只是说“我的 shell 终止”而不澄清这一点,当你说“我的 shell”时,你的意思是你正在编写的程序。

标签: shell pipe exec fork


【解决方案1】:

嗯,这是一段很长很复杂的代码,逻辑看起来 而是临时的。我要花很长时间来剖析整个 东西。

我确实观察到你fork() 只有一次,然后每个分支都会调用 execlp() 运行管道中的两个进程之一。那离开 没有进程继续运行 shell。所以你真的需要fork() 两次。

假设原始进程是A。第一次调用后 fork() 我们有原始流程A 和孩子A1A 然后打电话 wait() 暂停直到 A1 终止。 A1 再次致电 fork() 并 运行流水线命令。

或者类似的东西。看着我的代码库,我看到了我最后一次 在 2000 年试验过这些东西,而我没有做两次 像你一样的子流程。但这应该是正确的一步 无论如何,方向。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多