2016-03-02 17 views
5

Sto implementando una shell.Perché execvp() viene eseguito due volte utilizzando fork()?

Quando si tenta un comando diverso dalla modifica delle directory, viene eseguito execvp(), il figlio termina e viene creato un nuovo figlio. Quando cambio le directory, il bambino non termina e viene creato un nuovo figlio. Ecco un esempio del mio codice:

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; viene eseguito correttamente, tranne che devo Ctrl+D due volte per terminare il programma.

Sebbene, se instrado le stesse informazioni (ad esempio mybash < chdirtest), viene eseguito correttamente una volta, termina il bambino, viene eseguito nuovamente tranne nell'originale direttamente, quindi termina l'ultimo figlio.

+3

Quando si esegue 'cd' il codice (incompleto) come spettacolo sarà non invocare' execvp'. Invece eseguirà il 'chdir' e quindi continuerà a eseguire la prossima iterazione' for' che invocherà 'fork'. Ecco perché il primo processo figlio non esce per il caso 'cd'. – kaylum

+4

Benvenuti in overflow dello stack. Si prega di leggere la pagina [Informazioni] a breve. La mia impressione immediata è che qui non ci siano abbastanza informazioni per essere in grado di rispondere: il diavolo si trova nei dettagli e mancano i dettagli. Tuttavia, @kaylum si trova almeno su parte del problema e probabilmente ha identificato il problema principale. (Osserverò che i condizionali dopo 'if (pid == 0)' mi pietrificano - non sono sufficienti parentesi, e nessun errore di gestione se 'execvp()' o 'chdir()' fallisce.) Leggete come per creare un MCVE ([MCVE]) e quindi fornire uno. –

+1

@kaylum Non voglio 'cd' richiamare' execvp() '. Voglio che cambi la directory, esegui il loopback, quindi esegui la riga successiva senza i problemi indicati. –

risposta

5

cd non dovrebbe essere invocato tramite un processo figlio, la shell stessa dovrebbe cambiare la sua directory corrente (che è la proprietà di un comando interno: modificare il processo della shell stessa).

Una shell (primitve) dovrebbe assomiglia:

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); 
    } 
}