这个shell在做什么?

时间:2014-02-26 05:51:13

标签: c shell

我看到这个代码作为如何制作一个迷你外壳的例子。但是我不知道它在做什么 - 我理解主要功能中的大多数事情,但它上面的函数初始化我真的很丢失。

任何关于shell如何工作的基础知识以及C中的一些低级函数都将非常受欢迎。

log_t Log;

void printLog(log_t *l){
  log_entry_t *tmp = l->tail;
  while(tmp != NULL){
    printf("%s\n", tmp->value);
    tmp = tmp->prev;
  }
}

int countArg(char *line){
  unsigned int i, count = 0;
  for(i = 0; i < strlen(line); i++){
    if(line[i] == ' ')
      count++;
  }
  return count + 1;
}

char **makeargv(char *line){
  char *buff;
  char **retv;
  unsigned int i, count, arg_num = 0;

  buff = malloc((strlen(line) + 1) * sizeof(char));
  strcpy(buff, line);

  arg_num = countArg(buff);

  retv = malloc((arg_num + 1) * sizeof(char*));

  retv[arg_num] = NULL;
  retv[0] = buff;

  for(i = 0, count = 1; buff[i]!='\0'; i++){
    if(buff[i] == ' '){
      buff[i]='\0';
      retv[count] = buff + i + 1; 
      count++;
    }
  }
  return retv;
}


int main()
{
  log_init(&Log);
  char * line;

  while(1){
    size_t size;
    char * cwd = NULL;
    char * query = NULL;
    char * match = NULL;

    int f_exit = 0,
    f_nbi=0,
    f_match=0,
    f_sys = 0,
    f_path=0;

    // print out the requested prompt
    cwd = getcwd(NULL,0); 
    printf("$(pid=%d)%s$ ", getpid(), cwd );
    free(cwd);

    line = NULL;
    fflush(stdout);
    getline(&line, &size, stdin);
    line[strlen(line)-1] = '\0';

    while(1){
      if(strcmp(line, "exit") == 0){
        if(f_match) printf("%s matches %s\n", query, line);
        f_exit = 1;
        printf("Command executed by pid=%d\n",getpid());
        log_destroy(&Log);
        break;
      }
      else if(strncmp(line, "cd ", 3) == 0){
        if(f_match) printf("%s matches %s\n", query, line);
        printf("Command executed by pid=%d\n",getpid());
        log_push(&Log, line);
        if(chdir(line + 3) != 0){
          printf("%s: No such file or directory\n",(line + 3));
        }
        break;
      }
      else if(strcmp(line, "!#") == 0){
        if(f_match) printf("%s matches %s\n", query, line);
        printf("Command executed by pid=%d\n",getpid());
        printLog(&Log);
        break;
      }
      else if(strstr(line,"!")==line){
        if(f_match) printf("%s matches %s\n", query, line);
        query = line+1;
        match = log_search(&Log, query);

        if(match==NULL){
          printf("Command executed by pid=%d\n",getpid());
          printf("No Match\n");        
          break;
        }
        else{
          f_match = 1;
          printf("Command executed by pid=%d\n",getpid());
          line = malloc((strlen(match)+1)*sizeof(char));
          strcpy(line, match);
          continue;
        }
      }
      else{
        f_nbi = 1;
        log_push(&Log,line);
        if(strstr(line,"/"))
          f_path = 1;       
        break;
      }
    }

    if(f_exit)
      break;

    if(f_nbi){
      pid_t pid = fork();
      if(pid == 0){ //child
        if(f_match){
          printf("%s matches %s\n", query, line);
          free(query-1);
        }

        printf("Command executed by pid=%d\n",getpid());
        char **argv = makeargv(line);
        f_sys = 0;

        if(f_path)
          f_sys = execv(argv[0],&argv[0]);
        else
          f_sys = execvp(argv[0],&argv[0]);

        if(f_sys == -1)
          printf("%s: not found\n",line);

        free(argv[0]);
        free(argv);
        log_destroy(&Log);
        exit(0);

    } 
    else { //parent
      waitpid(pid, NULL, WUNTRACED);
      if(f_match)
        free(query-1);
      }  
    }
    free(line);
    line = NULL;
  }
  if(line != NULL){
    free(line);
    line = NULL;
  }

  return 0;
}

1 个答案:

答案 0 :(得分:0)

printLog()函数只是打印log_t给定名称为typedef的结构类型的记录链接列表中的所有数据。它从列表的尾部开始并向后工作。目前尚不清楚该列表是单链接还是双链接,但prev通常只出现在双链表中。

countArgs()函数是确定命令行中存在多少个参数的粗略方法。它很粗糙,因为它没有考虑引号或多个相邻的空格。然而,这些仅仅意味着它高估了论证的数量,这并不严重。它不会将制表符识别为分隔符,这对于shell来说是不常见的。

makeargv()函数将命令行拆分为一系列空格分隔的单词,并将单词列表返回给调用函数。它有效地解析命令行,确保命令行末尾有一个空指针。同样,它是简单的,但足够。与其他两个函数相比,它的命名也不一致。