2016-03-02 107 views
5

我正在實現一個shell。爲什麼execvp()使用fork()執行兩次?

嘗試執行除更改目錄之外的命令時,execvp()運行時,子項終止並創建新的子項。當我改變目錄時,孩子不會終止並創建一個新的孩子。這裏是我的代碼示例:

for(;;) { 
    printf("bash: "); 
    parse(); 
    ... 
    pid_t pid = fork() 
    if (pid == 0) 
     if (!strcmp(line[0], "cd")) 
      if (!line[1]) (void) chdir(getenv("HOME")); 
      else (void) chdir(line[1]); 
     else execvp(line[0], line); 
    ... 
    if (pid > 0) { 
     while (pid == wait(NULL)); 
     printf("%d terminated.\n", pid); 
    } 
} 

cd ../; ls;運行正常,但我不得不Ctrl+D兩次以結束該程序。

雖然,如果我輸入相同的信息(即mybash < chdirtest),它會正確運行一次,終止子進程,再次運行,除非在原始進程中直接運行,然後終止最終的子進程。

+3

當你運行'cd'的(不完全)代碼顯示不會調用'execvp'。相反,它會執行'chdir',然後繼續運行下一個'for'循環迭代,它將調用'fork'。這就是爲什麼第一個子進程沒有爲'cd'情況退出的原因。 – kaylum

+4

歡迎使用堆棧溢出。請儘快閱讀[關於]頁面。我的直接看法是沒有足夠的信息讓我們能夠回答 - 魔鬼處於細節中,細節缺失。然而,@ kaylum至少是問題的一部分,並且可能已經確定了主要問題。 (我會觀察到'if(pid == 0)'後的條件會使我僵化 - 沒有足夠大括號,並且如果execvp()或者chdir()失敗,則不會出現錯誤處理請閱讀創建一個MCVE([MCVE])然後提供一個。 –

+1

@kaylum我不想'cd'來調用'execvp()'。我希望它改變目錄,循環回來,然後運行下一行,而不會出現問題。 –

回答

5

cd不應該通過子進程調用,shell本身應該改變其當前目錄(這是內部命令的屬性:修改shell本身的進程)。

A(primitve)外殼應該是這樣的:

for(;;) { 
    printf("bash: "); 
    parse(); 

    // realize internal commands (here "cd") 
    if (!strcmp(line[0], "cd")) { 
     if (!line[1]) (void) chdir(getenv("HOME")); 
     else (void) chdir(line[1]); 
     continue; // jump back to read another command 
    } 

    // realize external commands 
    pid_t pid = fork() 
    if (pid == 0) { 
     execvp(line[0], line); 
     exit(EXIT_FAILURE); // wrong exec 
    } 

    // synchro on child 
    if (pid > 0) { 
     while (pid == wait(NULL)); 
     printf("%d terminated.\n", pid); 
    } 
}