简易的shell实现

这篇文章的内容主要是利用进程的创建,等待,终止,替换。这些知识来实现一个自己的简易shell
在这里插入图片描述

1. 大致思路

我们用了这么长的shell,它的大概过程是这样:
在这里插入图片描述
其实就是我们在不断的输入一个程序,然后执行它。因为这个shell是不断可以执行程序,所以应该是shell创建一个子进程来完成我们输入的命令。如下图所示:
在这里插入图片描述
所以要写一个shell,需要循环以下过程:
1. 获取命令行
2. 解析命令行
3. 建立一个子进程(fork)
4. 替换子进程(execvp)
5. 父进程等待子进程退出(wait)

2. 基本实现

首先,shell就是一个死循环,当我们输入一个命令结束后,他就会开始下一个命令:
在这里插入图片描述
第二步,我们要提示一下用户:
在这里插入图片描述
这里我们为什么要这样来刷新,因为我们\n它会换行,我们输入命令一般是在提示符后面输入,而不是在下一行输入。
在这里插入图片描述
我们定义一个数组来存放你的字符串,然后把输入的字符串存进数组里:
在这里插入图片描述
这里我们一定要把回车清理,因为回车也是一个字符(\n)。我们这里用的fgets函数,可以看一下它的语法:
在这里插入图片描述
第三步,我们需要把输入的字符串按空格分割。因为在程序替换时,它是一个一个分开传的,我们可以把分割后的字符串放进一个数组里。
在这里插入图片描述

在这里插入图片描述
= 是故意这么写的,strtok 截取成功,返回字符串其实地址,截取失败,返回NULL。
这个strtok函数不理解的可以看这个文章:字符函数和字符串函数
第四步,我们创建一个子进程去进行程序替换:
在这里插入图片描述
我们来看一下运行结果:
在这里插入图片描述
我们可以看到大致是没有问题的。

3. 额外拓展

3.1 让文件带上颜色

我们平时用的shell,像可执行程序是绿色的,目录是蓝色的。那我们该如何实现呢?
首先,有一个alias的命令,它的意思是别名。
在这里插入图片描述
我们可以看到:myls和ls -a -l执行的一样的,但本质还是ls。那么我们可以看一下系统里的ls。
在这里插入图片描述
这个alias的意思是别名。ls本身是不带颜色的,但是加上一些其它选项。所以,我们自己写的时候,子进程程序替换找的是系统的ls,没有加上后面的选项。
在这里插入图片描述
所以遇到ls命令时,可以在下标为1的数组里加上这个选项。

3.2 内建命令

在这里插入图片描述
这个现象,我们可以看出我们cd过后,路径没有变化这是为什么。
在这里插入图片描述
从这里可以看出,我们用的cd可能不是/usr/bin目录下的。那这个cd是什么呢?
如果直接exec*执行cd命令,最多只是让子进程进行路径切换,但子进程是一运行就完毕的进程。但是在shell中,我们更希望父进程(shell本身)进行路径切换,因为父进程路径发生变化,后面的子进程也会继承父进程的路径

如果有些行为,是必须让父进程shell执行的,不想让子进程执行的,绝对不能创建子进程。只能父进程自己实现对应的代码,由shell自己执行的命令,我们称之为内建(bind-in)命令。相当于shell内部的一个函数

我们先看一下这个函数chdir:
在这里插入图片描述
这个系统调用函数意思是:用于改变当前工作目录,其参数为path 目标目录,可以是绝对目录或相对目录。
在这里插入图片描述
在这里插入图片描述
command_arge[1]里面存的就是目标路径。我们看一下运行结果:
在这里插入图片描述
这样就完美的解决了。那么有哪些内建命令呢?cd,export,echo这些都是。

3.3 添加环境变量

在这里插入图片描述
我们来看一下这样的运行结果:
在这里插入图片描述
所有的程序替换,如果我们不传环境变量,那么它会默认继承父进程的环境变量列表

在前面,我们使用带e的exec函数时。自己传环境变量,它会覆盖系统的环境变量,那么我们该如果添加式的传环境变量,而不是覆盖式的呢
在这里插入图片描述
在这里插入图片描述
从这个结果可以看到,我们在myshell里export没有办法添加,我们也不能使用environ指针去改变环境变量数组。我们可以使用一个putenv的函数:把字符串加到当前环境中
在这里插入图片描述
我们先来演示一下:
在这里插入图片描述
在这里插入图片描述
我们这样来做看能不能成功:
在这里插入图片描述
我们可以看到还是没有成功。原因是:
在这里插入图片描述
每次循环时,它会重新初始化数组。这样我们写的环境变量的内容下一次就没了,所以我们需要自己保存一下环境变量内容。
在这里插入图片描述
这里的env_buffer如果我们不想消失可以用动态开辟的,如果我们想存多个环境变量可以用二维数组。
在这里插入图片描述
此时我们再测试一下:
在这里插入图片描述
我们看到成功添加了环境变量。

3.4 重定向的实现

在这里插入图片描述
这是我们平时用重定向的方法,左边是一个完整的命令,右边是一个文件,把本来输入到显示屏上,重定向到文件中。
在这里插入图片描述
那么在获取用户输入后,它有这几种情况:ls -a -l>log.txt or cat<file.txt or ls -a -l>>log.txt or ls -a -l,原来下面写的是分析命令的过程。那么我们就要在这两个之间完成打开文件和重定向的工作。

那么我们就写一个函数来检查是否重定向:
在这里插入图片描述
那么我们就需要从头开始遍历一遍:
在这里插入图片描述
如果我们遇到了一个大于符号,那么我们还要进一步判断它下一个位置:
在这里插入图片描述
情况分好之后,我们可以定义一些标识符:
在这里插入图片描述
以输出重定向为例
第一步:将遇到的符号改成\0
在这里插入图片描述
DROP_SPACE这个意思是:把符号后面的空格去掉。
在这里插入图片描述
在这里插入图片描述
我们把信息记录下来,其它两个也是一样的道理。
在这里插入图片描述
在每次循环开始,把文件信息和重定向信息重新设置一下:
在这里插入图片描述
到这里,我们重定向信息已经整理好了,现在我们需要完成重定向了。
在这里插入图片描述
这里程序替换,会影响曾经子进程打开的文件吗
不影响,程序替换只会影响该进程的代码和数据,曾经子进程打开的文件是内核数据,程序替换不会影响

这里在open第三个参数:在创建文件时,设置文件访问权限的初始值。我们创建时,还是设置一下,不然创建出来是随机值。第三个参数是在第二个参数中有O_CREAT时才用作用。若没有,则第三个参数可以忽略

运行结果如下
在这里插入图片描述

总结
1. 环境变量的数据,保存在进程的上下文中。
2. 环境变量会被子进程继承下去,所以会有全局属性。
3. 当我们进行程序替换的时候,当前进程的环境变量非但不会被替换,而且会继承父进程的

在这里插入图片描述

  • 13
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学代码的咸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值