Shell的本质:
首先要明确一点:shell是我们未来所以进程的父进程。

shell想要执行命令,就需要从命令行中获取我们输入的字符串,shell会不断获取,所以其实,shell的本质其实是一个死循环!
并且,如今我们使用的大部分软件都是一个死循环,就比如说:你在看我这篇博客时,你不点击右上角的'x',这个软件就不会自动退出,而是一直维持当前循环。
1.打印命令行:

此时,我们的shell打印除了命令行之后,就因该从键盘中获取我们的输入
2.获取输入信息:
fgets():

fgets()可以从指定的文件(stream)中,获取到字符串s,该字符串的长度为参数size

封装函数:

3.解析字符串
我们需要将命令行字符串从"ls -a -l" 解析为 "ls" "-a" "-l"
最终目的:

切割方法:strtok
strtok的使用方法:


命令行解析命令:bash来解析命令行,其实和我们手搓的解析类似,都需要将一个字符串分割成一个一个小的命令,制成一个命令行参数表
4.执行命令
在第三步中,我们就已经将命令一个一个解析到了我们的命令行参数表了,所以想要执行命令,就只用一个一个执行命令行参数表中的内容即可。

最终,我们就完成了我们自己的shell,通过完成自主shell的过程,我们可以更清晰地了解到:shell其实就是一个死循环的过程,其命令运行的本质也是进程替换!
不过,我们这个shell对于所有的命令,都是让子进程去执行的,那么是否有一些指令是只能由父进程来执行的呢?
cd ..:路径切换指令,该指令切换的是父进程bash的路径,再经由bash传递给子进程,这样才能改变每个进程的路径,才能真正完成路劲切换。
5.内建命令:

原因是因为:在我们获取主机名时,使用的是:getenv("HOSTNAME")直接使用的是环境变量,该环境变量是从父进程的环境变量中拿出来的,而当我们更改路径后,操作系统并不会自动更改环境变量中的路径。
我们使用chdir是用户层面的数据进行更改,并不是操作系统的数据进行了更改,所以,我们需要让bash自己更改环境变量!
法一:系统调用

那如果说一定要从环境变量中获取工作路径呢?
法二:环境变量
既然需要直接改变系统的环境变量,首先就要找到我们的路径:

此时我们就明确了目标:就是要将环境变量中的PWD直接进行修改!!!
snprintf()

该函数其实和printf类似,不过可以由我们指定打印的目标对象。

最终,我们就完成对环境变量的修改,也就可以直接从环境变量中获取信息!
不过,我们并没有给myshell写环境变量表啊?那么他的环境变量表从何而来呢?
答案是:当我们执行myshell.exe可执行文件时,也就创建了一个shell的bash的子进程,我们成shell的bash为父bash,而myshell的bash由于父子进程的继承性,也就继承了父bash的环境变量表,而当我们对myshell的环境变量表进行写入时,也就自动触发了"写实拷贝"此时父子进程的环境变量表也就彻底分开了!此时,bash也就拥有了不同于父bash的环境变量表!!!
6.myshll进一步优化
一、路径显示

我们只需使用从尾到头查找字符串,找到 '\' 时就对该字符串进行截取即可。

二、退出码

所以,接下来我们的目标就是让echo $?得到上一条命令的退出码!
首先,我们要明确一点,父进程是可以拿到子进程的退出码的!
分析原理,定义全局

退出码默认为0
status

原理回溯

由于更新的延迟性,下一条指令结束之前,lastcode中保存的就是上一条指令结束的退出码
最终实现

通过上述操做,我们就可以完成echo $?得到上一条指令的退出码!
然而,我们的实现是有局限性的,如果面临echo PATH等想要得到环境变量中的内容,myshell就只能对echo命令进行回显,而不会打印真正的环境变量,这也就意味着我们需要做更多的关键词识别!!!

总结:
通过这篇文章,我们可以更好地理解shell底层运行的原理!
源代码: