• linux中实现自己的bash


    🐶博主主页:@ᰔᩚ. 一怀明月ꦿ 

    ❤️‍🔥专栏系列:线性代数C初学者入门训练题解CC的使用文章「初学」C++

    🔥座右铭:“不要等到什么都没有了,才下定决心去做”

    🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

            感觉,有很久都没有写博客,主要是最近学的内容难以理解,所以时间不太充足,就没有写博客的时间,今天为什么要这一篇文章呢?主要是我感觉实现一个自己的命令行小程序还是比较有趣的。

             我们平时都是在linux的shell命令行上直接输入指令,有没有想过自己也可以去实现一个,自己的bash呢?

            那就让我们一起来探索属于自己自己的bash 

    这次我就直接给出源代码,没有把其中的方法,单独拿出来分析,我主要觉得那样有点显得代码冗余,其实也不用担心看不懂,我在源码中加了很多注释,大家也不怕看不懂。其实这样做还有一个好处,就是我们可以直接复制到我们的linux文件中,直接运行。 

    源码 

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #define SIZE 100 //用于定义命令的最大长度
    8. #define NUM 1024 //用于定义命令参数的最多个数
    9. #define SEP " " //分割字符的时候,默认以空格作为分隔符
    10. char _cwd[1024]; //用于存储PWD的环境变量
    11. char env_val[1024]; //用于自定义一个环境变量,这里有一个缺点,就是env_val是一个数组,只能添加一个自定义的环境变量,下次添加时,就会覆盖上次添加的环境变量
    12. int lastcode=0; //用于定义最近一个进程的退出码
    13. //获取用户名字
    14. const char* getUsername(void)
    15. {
    16. const char* name=getenv("HOME");//getenv如果没有获取到环境变量会返回空值
    17. if(name)return name;
    18. else return "none";
    19. }
    20. //获取主机名字
    21. const char* getHostname(void)
    22. {
    23. const char* host=getenv("HOSTNAME");
    24. if(host)return host;
    25. else return "none";
    26. }
    27. //获取工作目录
    28. const char* getCwd(void)
    29. {
    30. const char* cwd=getenv("PWD");
    31. if(cwd)return cwd;
    32. else return "none";
    33. }
    34. //获取用户输入的命令
    35. int getUserCommand(char* usercommand,int num)
    36. {
    37. char* r=fgets(usercommand,num,stdin);
    38. if(r==NULL)
    39. return -1;
    40. usercommand[strlen(usercommand)-1]='\0';
    41. return strlen(usercommand);
    42. }
    43. //分割字符串
    44. int commandSplist(char* usercommand,char* argv[])
    45. {
    46. int argc=0;
    47. argv[argc++]=strtok(usercommand,SEP);
    48. while(argv[argc++]=strtok(NULL,SEP));
    49. return 0;
    50. }
    51. //执行命令
    52. int execute(char* argv[])
    53. {
    54. pid_t id=fork();
    55. if(id<0)return -1;
    56. else if(id==0)
    57. {
    58. //child
    59. execvp(argv[0],argv);//程序替换
    60. exit(1);//程序替换失败返回1
    61. }
    62. else
    63. {
    64. //farther
    65. int status=0;//保存子进程退出时的退出码和退出信号
    66. pid_t rid=waitpid(id,&status,0);//阻塞等待
    67. if(rid>0)
    68. lastcode=WEXITSTATUS(status);//获取子进程退出时的退出码
    69. }
    70. return 0;
    71. }
    72. //改变工作路径
    73. void cd(const char* path)
    74. {
    75. chdir(path);//改变工作路径
    76. //虽然路径改了,但是环境变量中PWD存储的工作路径并没有改变
    77. char temp[1024];
    78. getcwd(temp, sizeof(temp));
    79. sprintf(_cwd, "PWD=%s",temp);
    80. putenv(_cwd);//为什么这里putenv[temp]?因为temp是一个临时变量,putenv只是将temp这个指针放到环境变量体系中,当函数调用结束,指针就销毁了,这个工作路径的环境变量就访问不了了
    81. }
    82. //什么叫做内建命令:内建命令就是bash自己执行的,类似于自己内部的一个函数!
    83. //1.是内建命令 0不是内建命令
    84. //执行的是内建命令
    85. int doBuildin(char* argv[])
    86. {
    87. if(strcmp(argv[0],"cd")==0)//cd命令
    88. {
    89. char* path=NULL;
    90. if(argv[1]==NULL)
    91. path=".";
    92. else
    93. path=argv[1];
    94. cd(path);
    95. return 1;
    96. }
    97. else if(strcmp(argv[0],"export")==0)//export命令
    98. {
    99. if(argv[1]==NULL)return 1;
    100. strcpy(env_val,argv[1]);
    101. putenv(env_val);
    102. return 1;
    103. }
    104. else if(strcmp(argv[0],"echo")==0)//echo命令
    105. {
    106. char val_0=*argv[1];
    107. char* val=argv[1]+1;//argv[1]+1:例如$? 则argv[1]是$ argv[1]+1是?
    108. if(val_0=='$'&&strcmp(val,"?")==0)//我们定义?保存着最近一个进程的退出码
    109. {
    110. printf("%d\n",lastcode);
    111. lastcode=0;
    112. }
    113. else if(val_0=='$')
    114. {
    115. printf("%s\n",getenv(val));//打印环境
    116. }
    117. else//echo打印字符
    118. {
    119. printf("%s\n",argv[1]);
    120. }
    121. return 1;
    122. }
    123. else
    124. {
    125. //可以添加其他的内建命令
    126. }
    127. return 0;
    128. }
    129. int main()
    130. {
    131. while(1)
    132. {
    133. char usercommand[SIZE];//存储用户输入的命令
    134. char* argv[NUM];//存储命令行参数
    135. //打印命令行提示符
    136. printf("[%s@%s %s]$",getUsername(),getHostname(),getCwd());
    137. //输入命令
    138. int n=getUserCommand(usercommand, sizeof(usercommand));
    139. if(n<=0)continue;
    140. //分割字符
    141. commandSplist(usercommand, argv);
    142. //判断是否是内建命令
    143. n=doBuildin(argv);
    144. if(n==1)continue;
    145. //执行命令
    146. execute(argv);
    147. }
    148. return 0;
    149. }

     🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸 

  • 相关阅读:
    ABP微服务系列学习-搭建自己的微服务结构(三)
    easyswoole学习记录
    FRED案例:矩形微透镜阵列
    多架构环境下docker-compose部署rocketmq单机模式—— 筑梦之路
    Github 2024-04-18 开源项目日报 Top10
    Elasticsearch(一):ES简介及其发展历史与ELK
    聊聊机器如何“写“好广告文案?
    LQ0161 九数分三组【枚举+置换】
    什么是JavaScript的事件驱动编程(event-driven programming)?
    Python机器视觉--OpenCV入门--视频的加载,录制
  • 原文地址:https://blog.csdn.net/m0_67846057/article/details/134490094