zoukankan      html  css  js  c++  java
  • 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()确实是有问题:
    怎么修复此问题呢?其实在解析命令最后前,做一个判断既可:
    这时,再来试验:
    好了,先做到这,下节继续完善~
  • 相关阅读:
    494 Target Sum 目标和
    493 Reverse Pairs 翻转对
    492 Construct the Rectangle 构建矩形
    491 Increasing Subsequences 递增子序列
    488 Zuma Game 祖玛游戏
    486 Predict the Winner 预测赢家
    485 Max Consecutive Ones 最大连续1的个数
    483 Smallest Good Base
    Django Form组件
    Django Auth组件
  • 原文地址:https://www.cnblogs.com/webor2006/p/3852304.html
Copyright © 2011-2022 走看看