linux系统编程综合练习-实现一个小型的shell程序(二)

上节minishell当中,已经初步实现了一个简单命令的解析,这节来继续对更加复杂命令进行解析,包含:输入重定向的解析、管道行的解析、输出重定向的解析以及是否有后台作业的解析,如下:
下面对其进行实现,上节中实现了对单条命令的解析,如下:
这节因为是多条,所以解析命令的实现也得重新开始写,在写之前,先列一个实现步骤:
先写一个流程伪代码,交其框架定出来,然后再去实现一个个功能函数,最后整个功能完成,这是一个比较好的编码习惯,先全局,先局部:
下面先定义未实现的函数:
 
然后再定义用到的全局变量:
并且在extends.h文件中进行声明:
这时,先来make一下,看这些修改能否正常编译:
从中来看,目前这个简单命令的解析框架已经搭建完毕,接下来,则是一个个函数进行实现:
void get_command(int i):获取第几条命令:
在实现解析方法之前,需要重新定义一下我们的命令数据结构,因为这一次是由多个命令组成,而不是单个命令,那要定义成一个什么样的结构呢?
所以,我们的命令数据结构需调整为:
由于现在是多条命令解析,所以cmd需要将其声明为数组:
另外,对于是cmd的初始化操作也得进行变化:
在继续编写前,咱们先来编译一下,看是否能编译过,一步一步脚印,步步为营,这样编写能减少出错的机率:
出错了,这也说明好的编码习惯,得改一点,立马来确认是否能过编译通过,一点点往上加功能,这样也会比较踏实,好了解决错误,是由于在execute_command还是执行的单条命令,所以肯定会出错,先将其注释掉:
再来编译这次就ok了,下面开始进行解析,根据解析的示例图,需要将cmdline中的命令参数提取到avline数组中,所以声明两个变量来分别指向cmdline和avline:
下面开始一步步进行解析:
 
也就是这一步:
其实,这个解析还是有点问题,比如命令"cat < test.txt",依照上面编写的代码来分析,当解析完cat之后,因为遇到了' ',所以j++:
再次循环:
也就是cmd[i].args[1] = ' ';而实际上只有一个cat命令,并没有第二个参数,所以需要做如下处理:
/*
* 解析简单命令至cmd[i]
* 提取cmdline中的命令参数到avline数组中
* 并且将COMMAND结构中的args[]中的每个指针指向这些字符串
*/
void get_command(int i){
    /* cat < test.txt | grep -n public > test2.txt & */
    int j = 0;//代表命令中的参数个数
    int inword;//是否在单词中
    while(*lineptr != ''){
        /* 去除空格 */
        while(*lineptr == ' ' || *lineptr == '	')
            lineptr++;
     /* 将第i条命令第j个参数指向avptr */
        cmd[i].args[j] = avptr;
     /* 提取参数 */
while(*lineptr != '' && *lineptr != ' ' && *lineptr != ' ' && *lineptr != '>' && *lineptr != '<' && *lineptr != '|' && *lineptr != '&' && *lineptr != ' '){
       /* 参数提取至avptr指针指向的数组 */
*avptr++ = *lineptr++; inword = 1; } *avptr++ = ''; switch (*lineptr)//说明命令中的一个单词解析完 { case ' ': case ' '://表示一个命令的第一个参数已经解析完,应该继续解析其第二个参数,如:grep -n public,当解析完grep后,则会遇到空格,应该继续解析参数-n inword = 0; j++; break; case '<': case '>': case '|': case '&': case ' '://说明命令解析结束了 if(inword == 0) cmd[i].args[j] = NULL;//这时需要将空格参数去掉return; default: /* for '' */ return; } } }

这时,写了这么多代码,先编译一下:

可见代码现在没有什么问题,接下来实现check函数

int check(const char *str):判断命令是否包含某个字符:
 
怎么来理解上面的写法呢?
理解起来有点绕,可以好好消化下,接下来实现另外一个函数
void getname(char *name):获得重定向后的文件名:
另外,在parse_command()中,需要修改一个地方,就是对于输出重定向,可以有>>,表示追加的方式,所以改变如下:
需要定义一下append全局变量:
对于现在的代码,得验证其是否是正确的,所以,在程序还没有写完之前,可以写一个函数来打印解析的值进行验证程序的合法性,如下:
具体代码实现,比较简单,这里就不多解释了:
运行来验证下:
但是,如果直接回车,看结果:
所以,在init方法中,需将全局变量全部进行一次初始化:
这时再来看:
这时,应该是代码逻辑的问题,来看下代码parse_command()确实是有问题:
怎么修复此问题呢?其实在解析命令最后前,做一个判断既可:
这时,再来试验:
好了,先做到这,下节继续完善~
原文地址:https://www.cnblogs.com/webor2006/p/3852304.html