2012-09-22 14 views
5

Sto creando una shell semplice. Deve anche essere in grado di leggere file di testo per linee. Questo è il mio codice:fgets esegue il ciclo molte volte prima di uscire per EOF

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include <sys/stat.h> 

// Exit when called, with messages 
void my_exit() { 
    printf("Bye!\n"); 
    exit(0); 
} 

int main(void) { 

    setvbuf(stdout, NULL, _IONBF, 0); 

    // Char array to store the input 
    char buff[1024]; 

    // For the fork 
    int fid; 

    // Get all the environment variables 
    char dir[50]; 
    getcwd(dir,50); 
    char *user = getenv("USER"); 
    char *host = getenv("HOST"); 

    // Issue the prompt here. 
    printf("%[email protected]%s:%s> ", user, host, dir); 

    // If not EOF, then do stuff! 
    while (fgets(buff, 1024, stdin) != NULL) { 

    // Get rid of the new line character at the end 
    // We will need more of these for special slash cases 
    int i = strlen(buff) - 1; 
    if (buff[i] == '\n') { 
     buff[i] = 0; 
    } 

    // If the text says 'exit', then exit 
    if (!strcmp(buff,"exit")) { 
     my_exit(); 
    } 

    // Start forking! 
    fid = fork(); 

    // If fid == 0, then we have the child! 
    if (fid == 0) { 

     // To keep track of the number of arguments in the buff 
     int nargs = 0; 

     // This is a messy function we'll have to change. For now, 
     // it just counts the number of spaces in the buff and adds 
     // one. So (ls -a -l) = 3. AKA 2 spaces + 1. Really in the 
     // end, we should be counting the number of chunks in between 
     // the spaces. 
     for (int i = 0; buff[i] != '\0'; i++) { 
     if (buff[i] == ' ') nargs ++; 
     } 

     // Allocate the space for an array of pointers to args the 
     // size of the number of args, plus one for the NULL pointer. 
     char **args = malloc((sizeof(char*)*(nargs + 2))); 

     // Set the last element to NULL 
     args[nargs+1] = NULL; 

     // Split string into tokens by space 
     char *temp = strtok (buff," "); 

     // Copy each token into the array of args 
     for (int i = 0; temp != NULL; i++) { 
     args[i] = malloc (strlen(temp) + 1); 
     strcpy(args[i], temp); 
     temp = strtok (NULL, " "); 
     } 

     // Run the arguments with execvp 
     if (execvp(args[0], args)) { 
     my_exit(); 
     } 
    } 

    // If fid !=0 then we still have the parent... Need to 
    // add specific errors. 
    else { 
     wait(NULL); 
    } 

    // Issue the prompt again. 
    printf("%[email protected]%s:%s> ", user, host, dir); 
    } 

    // If fgets == NULL, then exit! 
    my_exit(); 
    return 0; 
} 

Quando eseguo da solo come un guscio, funziona benissimo. Quando eseguo ./myshell < commands.txt, non funziona.

ecommands.txt è:

ls -l -a 
pwd 
ls 

Ma l'output è:

>Bye! 
>Bye! 
>Bye! 
>Bye! 
>Bye! 
>Bye!>Bye! 
>Bye! 
>Bye! 
>Bye! 

non ha nemmeno eseguire il mio comando. Qualche idea? Pensavo che il mio ciclo temporale fosse piuttosto semplice.

+0

Prova e stampare il PID del processo in my_exit() per vedere chi stampa cosa. –

+0

È necessario almeno svuotare l'output dopo aver stampato il prompt in modo che risulti nel posto giusto rispetto all'output del comando. –

+0

Stampando il PID, ottengo tutti gli 0 (per ogni ciao!) Tranne l'ultimo, che è 19147 – user1687558

risposta

3

Non so se questo è il problema , ma (correttamente) menziono in un commento che si deve allocare "più uno per il puntatore NULL" nella matrice *args.

Tuttavia, in realtà non si imposta l'ultimo puntatore su *args su NULL.

execvp() non piace.

Questo non spiega perché potrebbe esserci una differenza tra input reindirizzati e non reindirizzati, a parte il comportamento non definito è un bastardo.

+0

Grazie - Ho impostato l'ultimo puntatore a NULL e lo strano comportamento si sta ancora verificando – user1687558

1

Ci scusiamo tutti: il mio file di testo era in una sorta di formato demente dalla GUI di TextEdit di Mac. Tutto funziona alla grande.

Apprezzo molto tutte le risposte utile

+0

Puoi approfondire ciò che era demente per il formato e come si manifestava la demenza? –

+0

Sicuro! Ho salvato il file TextEdit, ma era .rtf - quindi l'ho semplicemente rinominato in .txt ... Ciò ha provocato strani caratteri nella parte superiore del file (sul formato RTF), seguiti dai comandi. Quindi, quando il programma girava con l'input .txt, cercava di eseguire comandi completamente strani. Ho trovato questo provando cat commands.txt ... Il motivo per cui stavo usando TextEdit in primo luogo è perché sono stato SSH nel mio Unix Server attraverso il mio Mac @ home. Volevo creare un file di testo per i test, quindi l'ho creato in TextEdit e ho usato CyberDuck per SCP. – user1687558