自己的myshell 一、程序整体介绍1.1 myshell 的基本功能我们自己写的shell功能还很简陋可以执行最基本的查看当前目录看一下退出码看一下环境变量等一些功能1.2 Shell 的整体执行流程简单来说就是进入一个死循环然后进行一些操作进入特定的函数后执行命令二、头文件、宏定义与全局变量2.1 头文件的作用我们后面有一些操作这些头文件可以让我们操作更加方便不加的话就会失败2.2 MAXSIZE 与 MAXARGS 宏定义这些后续都会使用方便使用2.3 命令参数数组 gargv 与参数数量 gargc这个是命令行参数表用来存储用来存命令行参数后续有一个函数是保存命令行参数的2.4 环境变量数组 genv 与 genvc这个用来存储环境变量表2.5 分隔符 gsep后续会有函数分割这里方便分割2.6 cwd 与 lastcode 的作用保存我们工作路径然后还有和一个退出码我们后面都会使用的三、LoadEnv()——加载环境变量3.1 函数的作用用来获取环境变量函数一般来说我们是通过配置函数来的但是这个比较麻烦所以我们这里通过继承父进程的方法来获取环境变量3.2 environ 环境变量表与二级指针这里只做一个声明告诉编译器我们定义过这个函数这个是系统提供的环境变量表3.3 extern 关键字extern就是上面的含义3.4 遍历环境变量表其实说白了就是把父进程的环境变量拷贝到我们定义好的数组里面进行拷贝3.5 malloc() 动态申请内存就动态申请一下空间很简单3.6 strcpy() 复制环境变量进行拷贝3.7 NULL 结束标志NULL时结束标志我们把它放到最后面3.8 打印加载后的环境变量之后就是一个简单的打印函数全部打印出来就可以了四、rfindDir()——提取最后一级目录4.1 函数的作用与返回值为了找到我们所传进来的目录最后一个名字4.2 const string 参数的含义就是一个C字符串这个我们会进行传入4.3 rfind() 反向查找反向查找就是为了方便4.4 string::npos 的作用nops是C语言中的一个关键词这是告诉我们我们没有找到相对的也就是我们这里没有找到\这就说明我们没有找到最后一个名字4.5 substr() 截取字符串截取我们的字符串并进行返回4.6 完整执行示例五、获取 Shell 提示符所需的信息5.1 GetUserName()——获取用户名就是系统调用我们这里获取用户名5.2 GetHostName()——获取主机名5.3 GetPwd()——获取当前工作路径5.4 getenv() 获取环境变量获取变量的函数5.5 PrintCommandLine()——打印命令提示符5.6 c_str() 与字符串类型转换这里是为了格式统一我们上面用的是printf输出的这是C语言的我们这里获取的是C的所以我们需要转化一下5.7 fflush(stdout) 刷新输出缓冲区刷新一下缓冲区将他搞到屏幕上我们上面没有\r\n这些所以不会刷新六、GetCommand()——获取用户输入的命令6.1 函数的作用与参数获取我们在键盘上面输入的命令保存到我们这个数字里面6.2 fgets() 读取标准输入就是从键盘上面读取6.3 stdin 标准输入流这个意思就是键盘6.4 strlen() 获取字符串长度计算一下字符串的长度6.5 删除输入末尾的换行符因为我输入完毕之后会按一下回车这个也会被吸入所以我们需要处理一下这个问题把我们的回车给消除掉6.6 返回命令长度返回一下命令行的长度这个返回值不重要七、ParseCommand()——解析命令行参数7.1 函数的作用这个函数的目的就是拆分你把我们上面输入一串命令给拆分之后保存到我们的数组里面为了后面执行做准备7.2 gargc 初始化与 memset() 清空数组因为可能会循环所以每一次都去要清除之前的的数据命令7.3 strtok() 分割字符串分割字符我们一串命令是按照“ ”来分割的7.4 strtok(NULL, gsep) 的含义我们需要一直分割所以这里NULL就是告诉编译器接着上一次分割7.5 gargc 与 while 循环就是一个循环把我们所有的命令都给读入了7.6 参数数组 gargv 的最终结构他存的就是一个个命令7.7 命令解析实例ls -l /home就是存了ls-l/home这三个八、CheckBuiltinExecute()——内建命令处理8.1 函数整体逻辑这个是用来检查内建命令的因为有一些命令是需要shell自己做的这里我们就举两个echo一个是$?查看返回值的问题PATH就是用来查看环境变量与上面的对应了还有就是cd的问题8.2 strcmp() 判断命令类型检查命令我们这里是不是cd如果是我们就执行函数体内部8.3 cd 内建命令的实现执行函数8.4 chdir() 修改工作目录修改工作路径也就是我们后面cd跟着的8.5 getcwd() 获取当前工作目录这个函数的本质是看我们现在的工作目录从操作系统当中然后保存到我们的这个数组里面8.6 snprintf() 拼接环境变量字符串然后进行拼接就是为了看着好看一些也没有其他作用了8.7 putenv() 更新 PWD 环境变量因为我们上面是从操作系统中我们环境变量没有改这个函数就是该环境变量改到我们的这个目录下这个函数也是一个库函数8.8 echo $? 查询上一条命令的退出码这里就也是看我们上一次的退出码用来查看直接把我们的份这个全局变量拿出来就行8.9 echo $PATH 查询环境变量查看环境变量8.10 lastcode 与函数返回值的区别lsatcode是用来保存上一次的这个函数返回值方便我们查询九、ExecuteCommand()——执行外部命令9.1 函数整体执行流程就是执行这些外部命令通过父子进程和进程替换来实现9.2 fork() 创建子进程创建子进程让子进程自己运行我们的命令这样不会影响我们下面的代码9.3 fork() 的返回值与父子进程分支判断不同返回值从而执行不同的命令9.4 execvpe() 执行程序替换进行程序替换9.5 execvpe() 三个参数的含义第一个参数我们要执行的路径传递命令行参数就是我们执行的具体的是什么路径我们上面切割过传递环境变量我们保存过9.6 execvpe() 成功与失败的执行流程如果成功就不会执行exit1此时返回值就是普通的命令返回值如果返回值为1就说明执行失败了9.7 waitpid() 等待子进程结束父进程等待子进程执行完毕并接收返回值9.8 status 保存子进程退出信息status保存了我们退出码和信号码9.9 WEXITSTATUS() 提取退出码这里就是提取退出码十、main()——主函数解析10.1 LoadEnv() 初始化环境变量初始化我们的环境变量我们之前写的函数吗继承父进程的环境变量10.2 定义命令输入缓冲区用来保存我们的命令10.3 while(1) 实现 Shell 循环死循环用来执行我们的shell10.4 PrintCommandLine() 打印提示符10.5 GetCommand() 获取命令获取失败就是继续执行从头再来10.6 ParseCommand() 解析命令解析我们输入的命令10.7 CheckBuiltinExecute() 处理内建命令内部命令10.8 ExecuteCommand() 执行外部命令外部命令