输入之后,我们自然需要去进行获取,我们需要分割命令行,这个地方用strtok。把字符串切割成若干个子串:
strtok:第一次直接传递参数,第二次则必须传NULL。且在最终strtok会返回NULL。
- fork创建进程
利用fork创建子进程,同时父进程需要等待子进程退出返回结果
另外我们还需要选择替换函数execvp:首先替换函数需要先带上v,可将所有的执行参数放入数组中统一传递,其次还要选择带上p,我们输入的只有程序命令,带上p会自动在环境变量中寻找
至此,基本的框架我们已经搞定了。
- shell运行原理
同时,在理解一下shell的运行原理:shell内部提取命令行做分析,然后调用exec. shell执行命令必须通过创建子进程,如果不创建子进程会把我们所有的shell全部替换,所以执行命令时一般磁盘上的程序必须创建子进程
- 内建命令
我们在运行自己写的shell的时候,发现输入cd …输入cd path等命令时发现路径并没有改变!
没有发生改变是因为自己写的shell执行很多命令都要fork()创建子进程,让子进程执行的cd,子进程有自己的工作目录,所以更改的子进程的目录,子进程执行完毕,继续用的是父进程,既shell,并没有影响父进程,所以并没有改变。
对于cd,我们可以采用内建命令:不需要创建子进程执行,让shell自己执行命令,称为内建命令。本质就是执行系统接口,我们可以调用一个系统接口chdir,可解决上述问题:
简易shell——代码实现
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#define NUM 1024
#define OPT\_NUM 64
char lineCommand[NUM];
char \*myargv[OPT_NUM];
int lastCode = 0;
int lastSig = 0;
int main()
{
while(1)
{
//输出提示符
printf("用户名@主机名 当前路径#");
fflush(stdout);
//获取输入
char\*s = fgets(lineCommand,sizeof(lineCommand)-1,stdin);
assert(s != NULL);
(void) s;
lineCommand[strlen(lineCommand)-1] = 0;
// printf("test:%s\n",lineCommand);
//ls -a -l -i 字符串切割
myargv[0] = strtok(lineCommand," ");
int i = 1;
if(myargv[0]!= NULL&& strcmp(myargv[0],"ls") == 0)
{
myargv[i++] =(char\*)"--color=auto";
}
//如果没有子串,strtok会返回NULL
while(myargv[i++] = strtok(NULL," "));
//如果是cd命令, 不需要创建子进程,让shell自己执行对应的命令,本质就是执行系统接口
//像这种不需要我们的子进程来执行,而是让shell自己执行的命令 --内建 内置命令
if(myargv[0]!=NULL&& strcmp(myargv[0],"cd")==0)
{
if(myargv[1] != NULL) chdir(myargv[1]);
continue;
}
if(myargv[0]!=NULL&& myargv[1]!=NULL && strcmp(myargv[0],"echo")== 0)
{
if(strcmp(myargv[1],"$?") == 0)
{
printf("%d %d\n",lastCode,lastSig);
}
else
{
printf("%s\n",myargv[1]);
}
continue;
}
//利用条件编译测试代码是否成功
#ifdef DEBUG
for(int i = 0;myargv[i];i++)
{
printf("myargv[%d]:%s\n",i,myargv[i]);
}
#endif
//执行命令
pid\_t id = fork();
assert(id!=-1);
if(id == 0)
{
execvp(myargv[0],myargv);
exit(1);
}
int status = 0;
pid\_t ret = waitpid(id,&status,0);
assert(ret > 0);
(void)ret;
lastCode = ((status>>8)&0xFF);
lastSig = (status & 0X7F);
}
return 0;
}
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**