🐶博主主页:@ᰔᩚ. 一怀明月ꦿ
❤️🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++
🔥座右铭:“不要等到什么都没有了,才下定决心去做”
🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀
感觉,有很久都没有写博客,主要是最近学的内容难以理解,所以时间不太充足,就没有写博客的时间,今天为什么要这一篇文章呢?主要是我感觉实现一个自己的命令行小程序还是比较有趣的。
我们平时都是在linux的shell命令行上直接输入指令,有没有想过自己也可以去实现一个,自己的bash呢?
那就让我们一起来探索属于自己自己的bash
这次我就直接给出源代码,没有把其中的方法,单独拿出来分析,我主要觉得那样有点显得代码冗余,其实也不用担心看不懂,我在源码中加了很多注释,大家也不怕看不懂。其实这样做还有一个好处,就是我们可以直接复制到我们的linux文件中,直接运行。
- #include
- #include
- #include
- #include
- #include
- #include
-
- #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\n",lastcode);
- lastcode=0;
- }
- else if(val_0=='$')
- {
- printf("%s\n",getenv(val));//打印环境
- }
- else//echo打印字符
- {
- printf("%s\n",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;
- }
🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸