MENU

【C】简单的Shell实现

2025 年 07 月 20 日 •

前言

所谓Shell,其实只干了两件事:监听和执行命令

详细的代码参见我的Github库

监听

Shell是这样一个软件,持续监听用户的输入,然后处理用户输入的指令,执行相应的功能。

基本上,所有的软件都是由一个死循环构成的,在这个死循环中,不断地监听、执行,重复这样一个过程。

我们Shell的基本框架是:

int main(int argc, char **argv) {
  // 给定一个缓冲区,存储命令
  char* command = (char*)malloc(BUFFER_SIZE * sizeof(char));
  while(1) {
    printf("ToyShell> ");
    // 读取输入
    int status = ReadLine(command);
    // 判断输入
    if(status > 0) {
      char** token_list = ProcessLine(command);
      ExecuteCommand(token_list);
    } else if(status == INPUT_EOF) {
      printf("Exit!\n");
      break;
    } else if(status == ERR_EXPR_TOO_LONG) {
      FlushStdin();
    }
  }
  free(command);
  return 0;
}

执行命令

命令的执行通常依靠两个函数:forkexec,前者创建一个子进程,在这个子进程中执行命令,后者执行这个命令,具体的实现如下:

int ExecuteCommand(char **token_list) {
  pid_t command_pid;
  int status = 0;
  // 处理输入
  if(token_list[0] == NULL) {
    return SUCCESS;
  } else {if(strcmp(token_list[0], "cd") == 0) {
      return Command_cd(token_list);
    } else if(strcmp(token_list[0], "exit") == 0) {
      return Command_exit(token_list);
    }
  }
  // 创建子进程
  command_pid = fork();
  // 执行命令,并设置子进程/主进程的表现
  if(command_pid == 0) {
    if(execvp(token_list[0], token_list) == -1) {
      perror("Execute Error");
      exit(0);
      return ERR_FAILED_TO_EXEC;
    }
  } else if(command_pid > 0) {
    wait(&status);
  } else {
    perror("Fork Error");
    exit(0);
  }
  free(token_list);
  return SUCCESS;
}

后记

在这个基础上,可以编写一些内置的命令。