2009-11-07 151 views
9

我想在Unix中創建一個簡單的shell在C中。我已經能夠完成所有命令和執行的解析,但是我遇到了管道問題。我認爲問題在於我沒有連接到第二個命令輸入的正確管道。例如,如果我輸入「ls | wc」,它會在「wc」命令之後暫停,我認爲這是因爲它等待輸入。我認爲問題是當我使用dup2(閱讀[我],0),並沒有掛在正確的管道。問題與管道命令在C

我知道這是一個廣泛的問題,但如果有任何指標我可以得到,我將不勝感激。這是創建新進程並嘗試管道它們的代碼。

int fileds[2]; 
    int reading[num_cmds]; 
    int writing[num_cmds]; 

    int p; 
    for(p=0; p < num_cmds; p++) 
    { 
     reading[p] = -1; 
     writing[p] = -1; 
    } 

    int j; 
    for(j=0; j < num_cmds-1; j++) //Create pipes for commands 
    { 
     int fileds[2]; 
     pipe(fileds); 
     reading[j+1] = fileds[0]; 
     writing[j] = fileds[1]; 
    } 

    int i = 0; 
    for(i = 0; i < num_cmds;i++) 
    {   
     cmd_args = parse_cmd(cmds[i],output_file,input_file,&run_bg); //Get command and args 

     pid_t childpid; 
     int status; 
     childpid=fork(); 

     if (childpid >= 0) 
     { 
      if (childpid == 0) 
      {    
       if(writing[i] != -1) 
       { 
        dup2(writing[i],1); 
        close(writing[i]); 
       } 

       if(reading[i] != -1) 
       { 
        dup2(reading[i],0); 
        close(reading[i]); 
       } 

       int h; 
       for(h = 0; h < num_cmds; h++) 
       { 
        close(writing[h]); 
        close(reading[h]); 
       } 

       if(execvp(cmd_args[0],cmd_args) == -1) 
       { 
        perror("Problem with command"); 
        exit(0); 
       } 
      } 
      else 
      { 
       wait(&status); 
       int m; 
       for(m = 0; m < num_cmds; m++) 
       { 
        if(writing[m] != -1) close(writing[m]); 
        if(reading[m] != -1) close(reading[m]); 
       } 
      } 
     } 
     else 
     { 
      perror("fork"); 
      continue; 
     } 


     input_file[0] = 0; 
     output_file[0] = 0; 
     run_bg = 0; 
    } 

} 



更新:我能弄明白,感謝Richard。它是以錯誤的順序關閉文件描述符,而不是關閉一些文件描述符的組合。這是工作代碼。

int fileds[2]; 
    int reading[num_cmds]; 
    int writing[num_cmds]; 

    int p; 
    for(p=0; p < num_cmds; p++) 
    { 
     reading[p] = -1; 
     writing[p] = -1; 
    } 

    int j; 
    for(j=0; j < num_cmds-1; j++) 
    { 
     int fileds[2]; 
     pipe(fileds); 
     reading[j+1] = fileds[0]; 
     writing[j] = fileds[1]; 
    } 

    int i = 0; 
    for(i = 0; i < num_cmds;i++) 
    {   
     cmd_args = parse_cmd(cmds[i],output_file,input_file,&run_bg); 

     pid_t childpid; 
     int status; 
     childpid=fork(); 

     if (childpid >= 0) 
     { 
      if (childpid == 0) 
      {    
       if(writing[i] != -1) 
       { 
        close(1); 
        dup2(writing[i],1); 
       } 

       if(reading[i] != -1) 
       { 
        close(0); 
        dup2(reading[i],0); 
       } 

       if(execvp(cmd_args[0],cmd_args) == -1) 
       { 
        perror("Problem with command"); 
        exit(0); 
       } 
      } 
      else 
      { 

       wait(&status); 
       close(writing[i]); 

       if(i > 0) 
       { 
        close(reading[i]); 
       } 
      } 
     } 
     else 
     { 
      perror("fork"); 
     } 


     input_file[0] = 0; 
     output_file[0] = 0; 
     run_bg = 0; 
    } 

回答

2

我認爲你的問題可能是你等待循環內的每個進程,然後關閉所有的文件描述符。這使得下次調用dup2()時文件描述符無效,並導致下一個進程的stdin保持不變。

只是猜測,我沒有運行代碼。

+0

我認爲你是對的。我試着評論if(閱讀[m]!= -1)close(閱讀[m]);在循環中,這是讓我管道2命令。感謝您指點我正確的方向! – mbxtr 2009-11-08 00:25:10

0

當I型的「ls | WC」 WC確實按預期並打印由ls命令輸出的字的數量。請記住,當您使用「|」輸入管道命令時您不需要在應用程序中創建管道。第一個命令需要輸出到標準輸出,第二個命令需要讀取標準輸入。

+0

這是一個瞭解管道如何工作的項目,所以我需要能夠設置管道。 「ls | wc」在普通終端中工作,但我需要在該程序中模擬它。 據我所知,我需要設置第一個命令的輸出 - 在這種情況下,「ls」是管道的輸出,而第二個命令的輸入是管道的輸入。 – mbxtr 2009-11-07 23:11:22

+0

那麼,如果你正在實現一個shell來提供這個管道機制,那麼你確實需要使用管道或者類似的機制。我認爲提問者知道這些問題;他在問爲什麼它不起作用。 – BobbyShaftoe 2009-11-07 23:12:17