正好最近看了csapp,然后正好也借着这个机会补一补C语言,并且加深下自己的理解,于是开始动手自己写一个shell。
总体架构
总体架构其实非常非常简单,就是一个死循环,不停处理用户的输入,除非用户退出。所以在bash中,整体架构是这样子的:
- 初始化阶段。shell也会读取自己的配置文件,然后进行初始化。
- 解释阶段。shell会从标准输入、文件等地方获取命令并且执行。
- 终止阶段。shell执行关闭命令,并且释放内存,终止。
首先肯定从最简单的入手,那么只需要中间的解释阶段即可。
循环的实现
再次进行具体化,在循环里不停读取用户的输入,然后解析用户的输入,将其解析成对应的参数,最后执行就可以了,由此可以抽象出三个函数:
csh_read_line()
:获取用户的输入,其实有对应的c语言的封装可以非常容易获取用户输入的一行,不过这里打算还是老老实实写。csh_split_line(line)
:将用户的输入解析成对应的args的数组。csh_execute(args)
:真正执行用户的命令。
获取用户输入
由于不确定用户输入的一行到底有多长,所以我们需要使用malloc来动态分配内存。并且还需要注意,因为读到文件末尾之后会返回一个EOF,所以需要用int来接受(这点我不理解)。
1 | char *csh_read_line() |
其实上面的这么多,用标准库的一个函数就可以解决了。
解析用户的输入
这一步为了简化,就是直接利用中间的空格作为分隔符来进行分割,而且这个简单的shell并不支持引号,所以如果是echo 'a b'
这条命令,那么在正常的shell里面是会输出a b
的,但是在我们的shell里,会输出'a
和b'
。
1 | char **csh_split_line(char *line) |
其实核心就是strtok这个函数,就是利用这个获取到参数的。
执行用户的命令
这一部分反而是最简单的,因为它只需要利用fork创建一个子进程,然后利用exec对应的函数进行处理就可以了。
1 | int csh_launch(char **args) |
OK,到这里一个最简单的shell就写完了。