2015-02-09 39 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()爲什麼得到上一行?

嗨,我正在嘗試編寫一個shell程序,我不明白爲什麼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);'不需要。 – 2015-02-09 13:29:51

+0

'fflush(stdin);'不好。 – 2015-02-09 13:30:25

+3

'fflush()'沒有被定義爲輸入流(或輸入/輸出流,其中最後一個操作被輸入)。 – pmg 2015-02-09 13:30:26

回答

0

問題是argv是不是真的初始化,因爲你是在main()改變在tokenizer()當地的指針,而不是指針。

,你所要做的就是通過argv的地址,而不是指針本身,然後更改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,你用什麼程序來格式化我的代碼非常好? – 2015-02-09 13:44:19

+0

@BrianDoetsch沒有,我只是做了我自己。 – 2015-02-09 13:45:06

+0

與這些變化,我得到不兼容的指針類型 – 2015-02-09 13:52:40