2015-02-09 2 views
0
[email protected]:~/Documents/School$ ./shell 
Shell(pid = 6955) 1> ls 
command: ls 
argv[i] = ls 
argv[i] = ./shell 
Parent says 'child process has been forked with pid=6956' 
./shell 
Parent says 'wait() returned so the child with pid=-1 is finished' 
Shell(pid = 6955) 2> 

Это домашнее задание, над которым я работаю, но я немного в тупике.Почему getline() получает предыдущую строку?

Привет, Я пытаюсь написать программу оболочки, и я не понимаю, почему getline получает предыдущую строку ввода.

плюс программа выполнит 'ls -al,' pwd и несколько других. но не только ls.

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

int tokenizer(char *str,char **argv); 
void doCommand(char **argv); 

int main() 
{ 
    pid_t pid; 
    char *command; 
    int Num_bytes_read; 
    size_t nbytes = 60; 
    int NumCommand = 0; 
    char **argv; 

    int NumOfArgs; 

    command = (char *) malloc (nbytes + 1); 
    command = NULL; 
    while(1) 
    { 
     NumCommand++; 
     printf("Shell(pid = %d) %d> ",getpid(),NumCommand); 

     fflush(stdin); 

     Num_bytes_read = getline(&command,&nbytes,stdin); 

     printf("command: %s",command);   
     if(Num_bytes_read == -1) 
     { 
      printf("\n ERRor\n"); 
     } 
     else 
     { 
      int x = tokenizer(command,argv); 
      int i;   

      for (i = 0; i < (x+1); ++i) 
       printf ("argv[i] = %s\n",argv[i]); 
      //if (strcmp(argv[0], "quit")){ 
      //break; 
      //} 
      doCommand(argv); 
     } 
    } 
    return 0; 
} 

int tokenizer(char *str, char **argv) 
{ 
    //const char s[2] = " "; 
    char ** res = NULL; 
    char * p = strtok (str, " \n"); 
    int n_spaces = 0, i; 
    while (p) 
    { 
     res = realloc (res, sizeof (char*) * ++n_spaces); 
     if (res == NULL) 
      exit (-1); /* memory allocation failed */ 
     res[n_spaces-1] = p; 
     argv[n_spaces-1]= res[n_spaces-1]; 

     p = strtok (NULL, " \n"); 
    } 
    // realloc one extra element for the last NULL 

    res = realloc (res, sizeof (char*) * (n_spaces+1)); 
    res[n_spaces] = 0; 

    argv = res; 
    return n_spaces; 
}  

void doCommand(char **argv) 
{ 
    pid_t pid; 
    pid_t cpid; /* Pid of child to be returned by wait. */ 
    int fd[2]; // dual pipeline 
    int status; /* Exit status of child. */ 

    int nbytes; 
    int commandStatus; 

    pipe(fd); 

    pid = fork(); // Preceding with fork] 
    if (pid < 0) 
    { 
     printf("forking child process failed\n"); 
     exit(1); 
    } 
    else if (pid == 0)  // fork for the child 
    {  
     close(fd[0]); // close up reader side of pipe 

     cpid = getpid(); 

     /* Send "string" through the output side of pipe */ 
     write(fd[1], &cpid,sizeof(cpid)); 
     //argv[0] = "ls"; 
     //argv[1] = NULL; 
     commandStatus = execvp(*argv, argv); 
     if (commandStatus < 0) /* execute the command */ 
     {  
      printf("Try again, command failed\n"); 
      exit(1); 
     } 
    } 
    else if (pid > 1)    // fork for the parent 
    { 
     close(fd[1]); 

     /* Read in the child pid from the pipe */ 
     nbytes = read(fd[0], &cpid , sizeof(cpid)); 
     printf("Parent says 'child process has been forked with pid=%ld'\n",(long)cpid); 
     wait(NULL); 
     cpid = wait(&status);  /* wait for completion */ 

     printf("Parent says 'wait() returned so the child with pid=%ld is finished'\n",(long)cpid); 
    } 
} 
+0

'command = (char *) malloc (nbytes + 1);' не требуется. –

+0

'fflush (stdin);' нехорошо. –

+3

'fflush()' не определен для входного потока (или потока ввода/вывода, где была введена последняя операция). – pmg

ответ

0

Проблема заключается в том, что argv на самом деле не инициализируется, потому что вы изменяете локальный указатель в tokenizer(), вместо указателя в main().

То, что вы должны сделать, это пройти argv «s адрес, а сам указатель, а затем изменить tokenizer() как этот

int tokenizer(char *str, char ***argv) 
{ 
    char ** res  = NULL; 
    char * p  = NULL; 
    int  n_spaces = 0; 

    if ((str == NULL) || (argv == NULL)) 
     return 0; 

    p  = strtok (str, " \n"); 
    *argv = NULL; 
    while (p) 
    { 
     res = realloc (*argv, sizeof(char *) * ++n_spaces); 
     if (res == NULL) 
     { 
      free(*argv); 
      return 0; 
     } 
     res[n_spaces - 1] = p; 
     *argv    = res; 
     p     = strtok (NULL, " \n"); 
    } 
    res = realloc (*argv, sizeof(char *) * (n_spaces + 1)); 
    if (res == NULL) 
    { 
     free(*argv); 
     return 0; 
    } 
    res[n_spaces] = 0; 
    *argv   = res; 

    return n_spaces; 
} 

и главный

int x = tokenizer(command, &argv); 
/*      ^address of argv */ 

вы никогда не проверил последний realloc тоже, поэтому я исправил некоторые другие вещи, которые, я считаю, вы делали немного небезопасно.

exit() на malloc/realloc отказ не является действительно необходимым в вашем случае, вы можете просто free() уже alloced указатель и просто вернуть 0, то справиться с этим в main().

Кроме того, я рекомендую использование в const классификатором везде, где это имеет смысл, например

void doCommand(const char *const *argv) 

А также, не fflush()stdin это неопределенное поведение.

+0

Iharob, какую программу вы использовали для форматирования моего кода так красиво? –

+0

@BrianDoetsch Нет, я просто сделал это сам. –

+0

с этими изменениями, я получаю несовместимые типы указателей –