[Linux] Simulate the shell of Linux

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#define NUM 1024
#define SIZE 32
#define SEP " "

void showEnv()
{
    
    
  extern char** environ;
  int i;
  for(i = 0;environ[i];++i)
  {
    
    
    printf("%d:%s\n",i,environ[i]);
  }
}


int main()
{
    
    
  //保存输入的环境变量,防止顶替替换,如果地址变了环境就找不见了
  char myenv[32][256];
  int env_index = 0;
  int last_exit = 0;
  while(1)
  {
    
    
  //保存输入后的字符串
  char cmd_line[NUM];
  //保存打散后的字符串
  char *g_argv[SIZE];
  //打印出提示信息
  while(1)
  {
    
    
    printf("[root@localhost myshell]# ");
    //刷新缓冲区
    fflush(stdout);
    //对cmd_line进程初始化
    memset(cmd_line,'\0',sizeof cmd_line);
    //获取用户键盘输入
    if(fgets(cmd_line,sizeof cmd_line,stdin) == NULL)
    {
    
    
      continue;
      //输入错误就重新执行输入操作
    }
    //因为fgets是读取回车的,所以我们要把字符串的最后一位给去掉
    cmd_line[strlen(cmd_line)-1] = '\0';
    //这里读取写出来的都是一整串字符串,例如 ls -l -a
    // printf("echo: %s\n", cmd_line);
    // 那吗如果我们想要执行输入的命令就要对其进行分解
    // 分解成:"ls"  "-a"  "-l"
    g_argv[0] = strtok(cmd_line,SEP);//第一次调用的时候,要传入要分解的字符串,第二次调用的时候就可以将要分解的字符串位置写为NULL
 
    int index = 1;
 
    if(strcmp(g_argv[0], "ls") == 0)
        {
    
    
            g_argv[index++] = "--color=auto";
        }
        if(strcmp(g_argv[0], "ll") == 0)
        {
    
    
            g_argv[0] = "ls";
            g_argv[index++] = "-l";
            g_argv[index++] = "--color=auto";
        }
    
    while(g_argv[index++] = strtok(NULL, SEP));
    //因为我们这个原理为子进程替换,所以当执行cd命令的时候,我们就没有办法来返回,或者到达一个位置
    //内置命令, 让父进程(shell)自己执行的命令,我们叫做内置命令,内建命令
    //内建命令本质其实就是shell中的一个函数调用
    if(strcmp(g_argv[0],"cd") == 0)
    {
    
    
      if(g_argv[1]!=NULL)chdir(g_argv[1]);
      continue;
    }

    else if(strcmp(g_argv[0],"export") == 0)
    {
    
    
      //我们之前学到的命令几乎都是内建命令
      if(g_argv[1] != NULL)
      {
    
    
        strcpy(myenv[env_index],g_argv[1]);
        putenv(myenv[env_index++]);
      }
      continue;
    }
    else if(strcmp(g_argv[0],"env") == 0)
    {
    
    
      showEnv();
      continue;
    }
    else if(strcmp(g_argv[0],"echo") == 0)
    {
    
    
      const char* target_env = NULL;
      if(g_argv[1][0] == '$')
      {
    
    
        if(g_argv[1][1] == '?')
        {
    
    
          printf("%d\n",last_exit);
          continue;
        }
        else 
        {
    
    
          target_env = getenv(g_argv[1]+1);
          if(target_env != NULL)
          printf("%s=%s\n",g_argv[1]+1,target_env);
          continue;
        }
      }
    }
    //进行进程分割,子进程和父进程
    pid_t id = fork();

    if(id == 0)
    {
    
    
      //子进程
      printf("下面功能是子进程运行的\n");
      execvp(g_argv[0],g_argv);
      exit(1);
    }
    else if(id > 0)
    {
    
    
      int statu = 0;
      pid_t ret = waitpid(id,&statu,0);
      if(ret > 0) printf("exit code: %d\n", WEXITSTATUS(statu));
      if(ret > 0){
    
    
        last_exit = WEXITSTATUS(statu);
       printf("exit code: %d\n", WEXITSTATUS(statu));
      
    }
  
  }
  
  }  
  return 0;
}

Insert image description here

Guess you like

Origin blog.csdn.net/wh9109/article/details/132346777