2011-02-18 73 views
0

我試圖在Linux中開發一個shell作爲操作系統項目。其中一個要求是支持流水線(其中調用類似ls -l |的命令將第一個命令的輸出傳遞給第二個命令)。我試圖使用C管道()和dup2()命令,但重定向似乎沒有發生(少抱怨它沒有收到文件名)。你能確定我要去哪裏弄錯了嗎?我會怎樣去解決這個問題?在Linux shell中實現流水線

編輯:我想我需要使用freopen或fdopen某處,因爲我沒有使用read()或write()...是否正確?

(我聽說其他人已經完成了這個項目,使用freopen()是另一種解決這個問題的方法;如果你認爲這樣會更好,那麼也可以考慮一下去那個方向的提示。)

這裏是我的execute_external()函數,它執行所有非shell內置的命令。管道中的各種命令(例如[ls -l]和[less])存儲在命令[]數組中。

void execute_external() 
{   
    int numCommands = 1; 
    char **commands; 
    commands = malloc(sizeof(char *)); 

    if(strstr(raw_command, "|") != NULL)   
    { 
     numCommands = separate_pipeline_commands(commands); 
    } 
    else 
    { 
     commands[0] = malloc(strlen(raw_command) * sizeof(char)); 
     commands[0] = raw_command; 
    } 

    int i; 
    int pipefd[2]; 
    for (i = 0; i < numCommands; i++) 
    { 
     char **parameters_array = malloc(strlen(commands[i]) * sizeof(char *)); 
     int num_params; 
     num_params = str_to_str_array(commands[i], parameters_array); 

     if (numCommands > 1 && i > 0 && i != numCommands - 1) 
     { 
      if (pipe(pipefd) == -1) 
      { 
       printf("Could not open a pipe."); 
      } 
     } 

     pid_t pid = fork(); 


     pmesg(2, "Process forked. ID = %i. \n", pid); 
     int status; 
     if (fork < 0) 
     { 
      fprintf(to_write_to, "Could not fork a process to complete the external command.\n"); 
      exit(EXIT_FAILURE); 
     } 

     if (pid == 0) // This is the child process 
     { 
      if (numCommands > 1) { close(pipefd[1]); } // close the unused write end of the pipe 
          if (i == 0) // we may be pipelining and this is the first process 
      { 
       dup2(1, pipefd[1]); // set the source descriptor (for the next iteration of the loop) to this proc's stdout 
      } 
      if (i !=0 && (i != numCommands-1)) // we are pipelining and this is not the first or last process 
      { 
       dup2(pipefd[0], 0); // set the stdin of this process to the source of the previous process 
      } 
      if (execvp(parameters_array[0], parameters_array) < 0) 
      { 
       fprintf(to_write_to, "Could not execute the external command. errno: %i.\n", errno); 
       exit(EXIT_FAILURE); 
      } 
      else { pmesg(2, "Executed the child process.\n");} 
     } 
     else 
     { 
      if (numCommands > 1) { close(pipefd[0]); } // close the unused read end of the pipe 
      if (backgrounding == 0) { while(wait(&status) != pid); }// Wait for the child to finish executing 
     } 
     free(parameters_array); 
    } 
free(commands); 
    } 
+0

您應該描述你的問題得到答案。 – Simon 2011-02-18 04:49:32

+0

完成。不知道要描述多少,而不是輸出不能正確地重定向到下一個過程的輸入。 – 2011-02-18 04:55:18

回答

1

看起來你的代碼中有幾個bug正在進行。

首先,你所有的dup2只在孩子身上。爲了連接管道,您需要將父級的標準輸出複製到管道的寫入結束pipefd [1]。然後你會將讀取結束連接到標準輸入。

另外,它看起來像你的dup2的是向後與dup2 fildes複製到fildes2。所以當你重新分配標準輸入時,你需要dup2(in,0)和標準輸出你想dup2(out,1)。

所以管道代碼精簡片會是什麼樣子:

int pipefd[2]; 
pipe(pipefd); 

pid_t pid = fork(); 

if (pid == 0) //The child 
{ 
     dup2(pipefd[0], 0); 
} 
else 
{ 
     dup2(pipefd[1], 1); 
}