?博主主页:@ᰔᩚ. 一怀明月ꦿ
❤️?专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++
?座右铭:“不要等到什么都没有了,才下定决心去做”
???大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点???
感觉,有很久都没有写博客,主要是最近学的内容难以理解,所以时间不太充足,就没有写博客的时间,今天为什么要这一篇文章呢?主要是我感觉实现一个自己的命令行小程序还是比较有趣的。
我们平时都是在linux的shell命令行上直接输入指令,有没有想过自己也可以去实现一个,自己的bash呢?
那就让我们一起来探索属于自己自己的bash
这次我就直接给出源代码,没有把其中的方法,单独拿出来分析,我主要觉得那样有点显得代码冗余,其实也不用担心看不懂,我在源码中加了很多注释,大家也不怕看不懂。其实这样做还有一个好处,就是我们可以直接复制到我们的linux文件中,直接运行。
源码
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<sys/types.h>#include<sys/wait.h>#define SIZE 100 //用于定义命令的最大长度#define NUM 1024 //用于定义命令参数的最多个数#define SEP " " //分割字符的时候,默认以空格作为分隔符char _cwd[1024]; //用于存储PWD的环境变量char env_val[1024]; //用于自定义一个环境变量,这里有一个缺点,就是env_val是一个数组,只能添加一个自定义的环境变量,下次添加时,就会覆盖上次添加的环境变量int lastcode=0; //用于定义最近一个进程的退出码//获取用户名字const char* getUsername(void){ const char* name=getenv("HOME");//getenv如果没有获取到环境变量会返回空值 if(name)return name; else return "none";}//获取主机名字const char* getHostname(void){ const char* host=getenv("HOSTNAME"); if(host)return host; else return "none";}//获取工作目录const char* getCwd(void){ const char* cwd=getenv("PWD"); if(cwd)return cwd; else return "none";}//获取用户输入的命令int getUserCommand(char* usercommand,int num){ char* r=fgets(usercommand,num,stdin); if(r==NULL) return -1; usercommand[strlen(usercommand)-1]='\0'; return strlen(usercommand);}//分割字符串int commandSplist(char* usercommand,char* argv[]){ int argc=0; argv[argc++]=strtok(usercommand,SEP); while(argv[argc++]=strtok(NULL,SEP)); return 0;}//执行命令int execute(char* argv[]){ pid_t id=fork(); if(id<0)return -1; else if(id==0) { //child execvp(argv[0],argv);//程序替换 exit(1);//程序替换失败返回1 } else { //farther int status=0;//保存子进程退出时的退出码和退出信号 pid_t rid=waitpid(id,&status,0);//阻塞等待 if(rid>0) lastcode=WEXITSTATUS(status);//获取子进程退出时的退出码 } return 0;}//改变工作路径void cd(const char* path){ chdir(path);//改变工作路径 //虽然路径改了,但是环境变量中PWD存储的工作路径并没有改变 char temp[1024]; getcwd(temp, sizeof(temp)); sprintf(_cwd, "PWD=%s",temp); putenv(_cwd);//为什么这里putenv[temp]?因为temp是一个临时变量,putenv只是将temp这个指针放到环境变量体系中,当函数调用结束,指针就销毁了,这个工作路径的环境变量就访问不了了 }//什么叫做内建命令:内建命令就是bash自己执行的,类似于自己内部的一个函数!//1.是内建命令 0不是内建命令//执行的是内建命令int doBuildin(char* argv[]){ if(strcmp(argv[0],"cd")==0)//cd命令 { char* path=NULL; if(argv[1]==NULL) path="."; else path=argv[1]; cd(path); return 1; } else if(strcmp(argv[0],"export")==0)//export命令 { if(argv[1]==NULL)return 1; strcpy(env_val,argv[1]); putenv(env_val); return 1; } else if(strcmp(argv[0],"echo")==0)//echo命令 { char val_0=*argv[1]; char* val=argv[1]+1;//argv[1]+1:例如$? 则argv[1]是$ argv[1]+1是? if(val_0=='$'&&strcmp(val,"?")==0)//我们定义?保存着最近一个进程的退出码 { printf("%d\",lastcode); lastcode=0; } else if(val_0=='$') { printf("%s\",getenv(val));//打印环境 } else//echo打印字符 { printf("%s\",argv[1]); } return 1; } else { //可以添加其他的内建命令 } return 0;}int main(){ while(1) { char usercommand[SIZE];//存储用户输入的命令 char* argv[NUM];//存储命令行参数 //打印命令行提示符 printf("[%s@%s %s]$",getUsername(),getHostname(),getCwd()); //输入命令 int n=getUserCommand(usercommand, sizeof(usercommand)); if(n<=0)continue; //分割字符 commandSplist(usercommand, argv); //判断是否是内建命令 n=doBuildin(argv); if(n==1)continue; //执行命令 execute(argv); } return 0;}
???如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! ???