PART 2: 使 Shell 能读取命令

来源:互联网 发布:配电网数据采集与监控 编辑:程序博客网 时间:2024/04/30 10:56

这篇文章是《动手写 Shell》系列文章的第 <2> 篇。上篇文章中,我们已经完成了我们动手 Shell 的第一步:Shell 的提示符。在这篇文章中,我们开始使得我们的 Shell 能够开始读取命令,并且做简单的分词,将命令与参数分开。

读取命令

0x00 readline 库的使用

在实现读取命令的方法中我们所使用到的库是 readline,其实我们使用 fgets() 方法也能达到目的,但是如果使用 fgets() 的话如果我们在使用 Shell 时输入错了命令不能通过退格键来撤销,因为 fgets() 是按字符进行读取的。

0x01 安装 readline 库

sudo apt-get install libreadline-dev

0x02 使用 readline 库

如果我们的程序中使用到了该库,需要在编译代码时需要链接到 libreadline

例:

gcc -o test test.o -I /usr/include -lreadline

处理命令

0x00 实现思路

对于一条命令

cmd para1 para2 […… paraN]

我们希望它能被识别成为:

命令: cmd
参数0: cmd
参数1: para1
参数2: para2
……
参数N: paraN

其实思路也是很简单:

我们需要一个command指针来存储命令,一个数组来存储命令。

需要两个指针来顺着我们的整条指令来移动,来获取到每一个命令或者参数。

一开始时:

两个指针 *start, *end都指向指令的开头

如果 *start, *end 指向空格,自动向后移动

此处输入图片的描述

定义一个计数器 count,然后 *end 指针开始向后移动,直到碰到空格或者换行符或者结束符

此处输入图片的描述

如果 count 为0,说明当前处理的是命令,定一个临时指针 *p,沿着 *end*start 移动,将其赋给 *commandparameter[0]count + 2.

如果 *end 为换行符或终止符则停止,否则,将 *end 赋给 *start,然后 *end 按上述方式继续向后移动,直到遇到空格,将 *start 赋给 parameters[count-1]count + 1.

此处输入图片的描述

重复以上工作,直到 *end 遇到终止符 \0 或者换行符 \n

0x01 实现代码

#include "lshell.h"#include <readline/readline.h>#include <readline/history.h>int read_command(char **command, char **parameters, char *prompt){    free(buffer);    buffer = readline(prompt);    if(feof(stdin))    {        printf("\n");        exit(0);    }    if(buffer[0] == '\0')    {        return -1;    }    int count = 0;    char *start, *end;    int isFinished = 0;    start = end = buffer;    while(isFinished == 0)    {        while((*start == ' ' && *end == ' ') || (*start == '\t' && *end == '\t'))        {            start++;            end++;        }        if(*end == '\0' || *end == '\n')        {            if(count == 0)            {                return -1;            }            break;        }        while(*end != '\0' && *end != '\n' && *end != ' ')        {            end++;        }        if(count == 0){            char *p = end;            *command = start;            while(p != start && *p != '/'){                p--;            }            if(*p == '/'){                p++;            }            parameters[0] = p;            count += 2;#ifdef DEBUG            printf("\ncommand:%s\n", *command);#endif // DEBUG        }        else if(count <= MAX_ARGS){            parameters[count-1] = start;            count++;        }        else{            break;        }        if(*end = '\0' || *end == '\n'){            *end = '\0';            isFinished = 1;        }        else{            *end = '\0';            end++;            start = end;        }    }    parameters[count-1] = NULL;#ifdef DEBUG    printf("input analysis:\n");    printf("command:[%s]\ncommand:[%s]\nparameters:\n",*command,parameters[0]);    int i;    for(i=0;i<count-1;i++)        printf("[%s]\n",parameters[i]);#endif    return count;}

完整代码详见:https://github.com/luoyhang003/linux_kernel_expriment/tree/master/exp2


本文的版权归作者 罗远航 所有,采用 Attribution-NonCommercial 3.0 License。任何人可以进行转载、分享,但不可在未经允许的情况下用于商业用途;转载请注明出处。感谢配合!

1 0