2012-09-22 16 views
5

Robię prostą powłokę. Musi także móc czytać pliki tekstowe po liniach. To jest mój kod:fgets pętle wiele razy przed wyjściem do 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; 
} 

Kiedy uruchamiam go samodzielnie jako skorupę, działa świetnie. Po uruchomieniu ./myshell < commands.txt, to nie działa.

commands.txt jest:

ls -l -a 
pwd 
ls 

ale wyjście jest:

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

nawet nie uruchomić moje polecenia. Jakieś pomysły? Myślałem, że moja pętla while była całkiem prosta.

+0

spróbować wydrukować PID procesu w my_exit(), aby zobaczyć, kto drukuje co. –

+0

Musisz co najmniej wypróżnić dane wyjściowe po wydrukowaniu monitu, aby pojawił się we właściwym miejscu w stosunku do wyjścia polecenia. –

+0

Wydrukując PID, otrzymuję wszystkie 0 (za każdą Bye!) Oprócz ostatniej, która jest 19147 – user1687558

Odpowiedz

3

Nie wiem, czy to jest problem, ale ty (prawidłowo) wspomnieć w komentarzu, że trzeba przeznaczyć „plus jedna na wskaźniku NULL” w tablicy *args.

Jednak nie ustawia się ostatniego wskaźnika w *args na NULL.

execvp() to nie polubi.

To nie wyjaśnia, dlaczego może istnieć różnica między przekazaniem przekierowanym a niezranicowanym, inne niż niezdefiniowane zachowanie to bękart.

+0

Dziękuję - Ustawiłem ostatni wskaźnik na NULL i dziwne zachowanie wciąż się pojawia – user1687558

1

Przepraszamy wszystkich - okazuje się, że mój plik tekstowy był w jakimś szalonym formacie z GUI TextEdit. Wszystko działa świetnie.

Naprawdę doceniam wszystkie pomocne odpowiedzi

+0

Czy możesz rozwinąć to, co było obarczone demencją odnośnie do formatu i jak manifestuje się demencja? –

+0

Pewnie! Zapisałem plik TextEdit, ale było .rtf - więc zmieniłem nazwę na .txt ... To spowodowało dziwne znaki u góry pliku (w formacie RTF), a następnie polecenia. Kiedy program działał z wejściem .txt, próbował wykonać całkowicie dziwne polecenia. Znalazłem to, próbując cat commands.txt ... Powodem, dla którego używałem TextEdit na pierwszym miejscu, jest fakt, że korzystałem z SSH na moim serwerze Unix przez mój Mac @ home. Chciałem stworzyć plik tekstowy do testowania, więc zrobiłem go w TextEdit i użyłem CyberDucka do SCP. – user1687558