PART 2: 使 Shell 能读取命令

举报
远航 | FIBOS 发表于 2020/12/02 23:45:29 2020/12/02
【摘要】 这篇文章是《动手写 Shell》系列文章的第 <2> 篇。上篇文章中,我们已经完成了我们动手 Shell 的第一步:Shell 的提示符。在这篇文章中,我们开始使得我们的 Shell 能够开始读取命令,并且做简单的分词,将命令与参数分开。 读取命令 0x00 readline 库的使用 在实现读取命令的方法中我们所使用到的库是 readline,其实我们使...

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

读取命令

0x00 readline 库的使用

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

0x01 安装 readline 库

sudo apt-get install libreadline-dev
  
 
  • 1

0x02 使用 readline 库

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

例:

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

处理命令

0x00 实现思路

对于一条命令

cmd para1 para2 […… paraN]
  
 
  • 1

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

命令: 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;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98

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


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

文章来源: blog.csdn.net,作者:冰水比水冰,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/luoyhang003/article/details/51226798

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。