• <Linux>简单的shell解释器


    目录

     一、命令分割

    二、fork()创建子进程

    三、全部代码


    shell解释器

    就像下面Centos的环境下的命令行,可以解析我们输入的指令来达到运行不同功能的实现;

    shelll条件:

    必须是永不退出的,常驻内存的,我们使用死循环来解决;

    输入的命令又指令和指令选项:ls -a -l,我们使用命令分割来进行区分

    命令分割后解析需要子进程来运行解析后的指令对应的进程,这里需要运行其他进程,但是又不能影响父进程,我们创建子进程用execvp进行程序替换,来实现运行不同指令的效果;

     一、命令分割

    我们需要将输入的指令和选项分割开,方便我们来解析指令;

     这里我们采用了字符串函数strtok()来分割

    1. g_argv[0] = strtok(cmd_line, SEP);//第一次调用,传入原始字符串
    2. int index = 1;
    3. if (strcmp(g_argv[0], "ls") == 0)
    4. {
    5. g_argv[index++] = "--color=auto";
    6. }
    7. while(g_argv[index++] = strtok(NULL, SEP));//第二次调用,如果还要解析,传入NUL

    二、fork()创建子进程

    将命令解析后,创建子进程使用execvp()替换函数,来进行程序替换,实现功能;

    这时的父进程只需要等待子进程正常退出即可;

    1. 64 //5.fork();
    2. 65 pid_t id = fork();
    3. 66 if (id == 0)// child
    4. 67 {
    5. 68 printf("功能子进程执行\n");
    6. 69 // cd 只影响当前的进程
    7. 70 execvp(g_argv[0], g_argv);//ls -a -l
    8. 71 exit(-1);
    9. 72 }
    10. 73
    11. 74 // father
    12. 75 int status = 0;
    13. 76 pid_t ret = waitpid(id, &status, 0);
    14. 77 if (ret > 0)
    15. 78 {
    16. 79 printf("exit code:%d\n", WEXITSTATUS(status));
    17. 80 }

    三、全部代码

    1. 1 #include <stdio.h>
    2. 2 #include <stdlib.h>
    3. 3 #include <string.h>
    4. 4 #include <unistd.h>
    5. 5 #include <sys/wait.h>
    6. 6 #include <sys/types.h>
    7. 7
    8. 8 #define NUM 1024
    9. 9 #define SIZE 32
    10. 10 #define SEP " "
    11. 11
    12. 12 //保存打散之后的命令行 字符串
    13. 13 char *g_argv[SIZE];
    14. 14 //保存完成的命令行
    15. 15 char cmd_line[NUM];
    16. 16
    17. 17 //shell运行原理
    18. 18 //通过让子进程执行命令,父进程等待&&解析命令
    19. 19 int main()
    20. 20 {
    21. 21 //0.命令行解释器, 一定是一个常驻内存进程,不退出
    22. 22 while (1)
    23. 23 {
    24. 24 //1.打印提示信息
    25. 25 // [mr@localhost myshell]#
    26. 26 printf("[my@localhost myshell]#");
    27. 27 fflush(stdout);
    28. 28 memset(cmd_line, '\0', sizeof cmd_line);
    29. 29 //2.获取用户键盘输入的各种指令和选项: “ls -a -l”
    30. 30 if (fgets(cmd_line, sizeof cmd_line, stdin) == NULL)
    31. 31 {
    32. 32 continue;
    33. 33 }
    34. 34 cmd_line[strlen(cmd_line) - 1] = '\0';
    35. 35
    36. 36 //printf("echo:%s\n", cmd_line);
    37. 37
    38. 38 //3.命令行字符串解析
    39. 39 g_argv[0] = strtok(cmd_line, SEP);//第一次调用,传入原始字符串
    40. 40 int index = 1;
    41. 41 if (strcmp(g_argv[0], "ls") == 0)
    42. 42 {
    43. 43 g_argv[index++] = "--color=auto";
    44. 44 }
    45. 45 while(g_argv[index++] = strtok(NULL, SEP));//第二次调用,如果还要解析,传入NUL
    46. 46
    47. 47 // for (index = 0; g_argv[index]; index++)
    48. 48 // {
    49. 49 // printf("g_argv[%d]:%s\n",index,g_argv[index]);
    50. 50 // }
    51. 51 //4.TODO 内置命令 :让父进程(shell)自己执行命令,叫做内置命令,内建命令
    52. 52 //内建命令本质就是shell中的一个函数调用
    53. 53 if (strcmp(g_argv[0], "cd") == 0) //not child excute, father excute
    54. 54 {
    55. 55 if(g_argv[1] != NULL)
    56. 56 {
    57. 57 chdir(g_argv[1]);
    58. 58
    59. 59 continue;
    60. 60 }
    61. 61 }
    62. 62
    63. 63
    64. 64 //5.fork();
    65. 65 pid_t id = fork();
    66. 66 if (id == 0)// child
    67. 67 {
    68. 68 printf("功能子进程执行\n");
    69. 69 // cd 只影响当前的进程
    70. 70 execvp(g_argv[0], g_argv);//ls -a -l
    71. 71 exit(-1);
    72. 72 }
    73. 73
    74. 74 // father
    75. 75 int status = 0;
    76. 76 pid_t ret = waitpid(id, &status, 0);
    77. 77 if (ret > 0)
    78. 78 {
    79. 79 printf("exit code:%d\n", WEXITSTATUS(status));
    80. 80 }
    81. 81 }
    82. 82
    83. 83 return 0;
    84. 84 }

     

  • 相关阅读:
    axios源码学习
    联邦学习综述四
    模拟京东快递单号查询 练习
    千亿母婴辅食赛道崛起,建立和完善行业标准迫在眉睫
    GIC/ITS代码分析(1)MADT表
    MAX24——3Dmax中出现蒙皮封套权重失效解决办法
    运行谷歌开源BERT程序时遇到的bug修改记录
    扩展翡蜀定理问题
    阿里工作8年,肝到P7就剩这份学习笔记了,已助朋友拿到10个Offer
    XDU2019级保研数据统计分析
  • 原文地址:https://blog.csdn.net/weixin_63246064/article/details/127102340