2016-11-20 32 views
-2

我想在c中編寫一個簡單的shell。現在我試圖讓管道工作。我有一個結構c我敢送入這個功能,它包含存儲管文件描述符pipfd的位置,並且包含了每個命令c->type的結束標記信息(這可以是| || & & &等)。 CommandPrev只是跟蹤最後一個命令,所以我可以看到命令之前是否有管道標籤。爲什麼我的管道不能互相交談?

我完成這項工作後,我給孩子的PID(返回值)waitpid伺候我execvp

稱爲當我運行的命令,例如echo foo | echo bar我得到bar作爲輸出完全一樣的命令我期望,一切都很好。我的問題是,當我嘗試運行任何實際上使用來自管道前半部分的輸入的命令時,一切都會卡住。如果我運行類似echo foo | wc -c的東西,我不會得到任何輸出,它會永遠掛起。

我可以看到這個功能對這些類型的命令完成,因爲我打印當它返回。發生的事情是,我用execvp調用的命令從來沒有發生,所以我的waitpid永遠等待。

我認爲不知我的我管的兩端之間的連接斷開。任何一件事都不會被寫入,或者它們永遠不會被讀取,或者管道的接收端從未意識到寫入方已經完成,並且只是等待着永遠。我立即在所有管道上關閉,所以我傾向於懷疑它的最後一個......但我真的不知道如何去測試這三種情況中的任何一種。

這是我的代碼:

pid_t start_command(command* c, pid_t pgid) { 
    (void) pgid; 

    // If its a pipe token, create a shared pipe descriptor 
    if (c->type == TOKEN_PIPE){ 
     pipe(c->pipefd); 
    } 

    // Fork a child process, run the command using `execvp` 
    pid_t child = fork(); 
    if (child == 0) { 
     // writing side of the pipe 
     if (c->type == TOKEN_PIPE){ 
      dup2(c->pipefd[WRITE_SIDE], STDOUT_FILENO); 
      close(c->pipefd); 
     } 
     // receiving side of the pipe 
     else if (commandPrev->type == TOKEN_PIPE){ 
      dup2(commandPrev->pipefd[READ_SIDE], STDIN_FILENO); 
      close(commandPrev->pipefd); 
     } 

     // run the command 
     if (execvp(c->argv[0], c->argv) == -1) { 
      // fork failed 
      exit(-1); 
     } 
    } 
    else{ 
     // clean up, clean up, everybody, everywhere 
     if (commandPrev->type == TOKEN_PIPE){ 
      close(commandPrev->pipefd); 
     } 
    } 
    printf("return %i\n", getpid()); 
    return child; 
} 

謝謝!

+0

檢查您的系統調用錯誤,它們不會自動打印。 'close(c-> pipefd);'似乎試圖關閉一個數組。 –

+0

對於殼牌規格和語言的知識將幫助人們回答的問題,請使用'shell'標籤。人們爲學校編寫玩具殼這一點非常非常少見。 –

+0

@CharlesDuffy我的壞!我不知道,對不起 – Twiigs

回答

0

正如其他評論者說,你看起來就像你試圖關閉一個陣列。 像這樣的東西應該更好地工作:

// writing side of the pipe 
if (c->type == TOKEN_PIPE){ 
    close(c->pipefd[READ_SIDE]); 
    dup2(c->pipefd[WRITE_SIDE], STDOUT_FILENO); 
    close(c->pipefd[WRITE_SIDE]); 
} 
// receiving side of the pipe 
if (commandPrev->type == TOKEN_PIPE){ 
    close(commandPrev->pipefd[WRITE_SIDE]); 
    dup2(commandPrev->pipefd[READ_SIDE], STDIN_FILENO); 
    close(commandPrev->pipefd[READ_SIDE]); 
} 

或者,也可以在父waitpid函數調用後關閉該管道的有效側。像這樣:

waitpid(child, &status, 0); 

if (commandPrev->type == TOKEN_PIPE){ 
    close(commandPrev->pipefd[READ_SIDE]); 
} 
if (c->type == TOKEN_PIPE){ 
    close(c->pipefd[WRITE_SIDE]); 
} 
相關問題