2012-09-22 30 views
5

Estoy haciendo un shell simple. También necesita poder leer archivos de texto por líneas. Este es mi código:inserta bucles varias veces antes de salir de 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; 
} 

Cuando lo ejecuto solo como un shell, funciona muy bien. Cuando ejecuto ./myshell < commands.txt, no funciona.

commands.txt es:

ls -l -a 
pwd 
ls 

Pero la salida es:

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

ni siquiera se ejecuta mis órdenes. ¿Algunas ideas? Pensé que mi loop while era bastante simple.

+0

Probar e imprimir el PID del proceso en my_exit() para ver quién está imprimiendo qué. –

+0

Necesita al menos enjuagar la salida después de imprimir el mensaje para que salga en el lugar correcto relativo al resultado del comando. –

+0

Imprimiendo el PID, obtengo todos los 0 (¡para cada adiós!) Excepto el último, que es 19147 – user1687558

Respuesta

3

No sé si este es el problema , pero que (correctamente) mencionado en un comentario que usted tiene que destinar "más uno para el puntero NULL" en la matriz *args.

Sin embargo, en realidad no establece el último puntero en *args en NULO.

execvp() no le gusta eso.

Eso no explica por qué puede haber una diferencia entre la entrada redirigida y la no redireccionada, aparte de que el comportamiento indefinido es un bastardo.

+0

Gracias - Establecí el último apuntador a NULL y todavía se está produciendo un comportamiento extraño – user1687558

1

Disculpa a todos - resulta que mi archivo de texto estaba en algún tipo de formato demente desde la GUI TextEdit de Mac. Todo está funcionando bien.

Realmente aprecio todas las respuestas votos

+0

¿Puede explicar lo que se demente sobre el formato y cómo se manifestó la demencia? –

+0

¡Claro! Guardé el archivo TextEdit, pero era .rtf, así que lo renombré a .txt ... Esto dio como resultado caracteres extraños en la parte superior del archivo (sobre el formato RTF), seguidos de los comandos. Entonces, cuando el programa se ejecutó con la entrada .txt, estaba tratando de ejecutar comandos completamente extraños. Lo encontré probando cat commands.txt ... La razón por la que estaba usando TextEdit en primer lugar es porque he estado ingresando SSH en mi servidor Unix a través de mi Mac @ home. Quería crear un archivo de texto para probarlo, así que lo hice en TextEdit y usé CyberDuck para SCP. – user1687558