博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用C实现模拟实现一个shell解释器(一)
阅读量:6433 次
发布时间:2019-06-23

本文共 3288 字,大约阅读时间需要 10 分钟。

版权声明:您好,转载请留下本人博客的地址,谢谢 https://blog.csdn.net/hongbochen1223/article/details/52330293

项目介绍

一直在想,linux的命令解释器是如何工作的,一直想着自己实现一个命令解释器。后来随着自己的学习以及对linux中终端的使用,对命令解释器有了一个简单的学习和了解。并且对其实现,从一开始的很简单,到后面有一些忌惮。命令解释器,顾名思义,就是对用户输入的命令,进行分析,然后按照用户的想法运行相应的命令,然后再将运行结果成现在用户眼中。

在了解了lex和yacc的相关知识之后,我觉着可以使用lex和yacc更加简单的实现命令解释器,但是后来在开发过程中,我觉着还是一步一步走,从最简单的使用C来解析用户输入的命令以及相关参数,先实现一个简单版本的命令解释器,然后再使用lex和yacc进行优化,使命令解释器能够解析更加复杂的命令,这基本上就是我的思路。

命令介绍

在我们现在使用的linux的终端中,也就是在POSIX标准下,命令分为内部命令和外部命令,当命令解释器遇到内部命令的之后,便直接运行内部命令,也就是说,内部命令是我们自己的实现的。而外部命令,当命令解释器遇到外部命令的时候,直接从系统中找到相应的应用程序,然后开启一个子线程来执行该程序。

下面是我们知道的相应的内部命令:

  • exit : 退出该shell程序
  • cd : 改变当前的工作目录
  • echo : 回显命令后面的字符串
  • export : 设置环境变量
  • history : 显示历史命令

当前实现一

下面我们来看一下,我现在的实现,后面这个代码会逐步跟进,同时在后面的文章中,将会讲解命令以及参数的相应的POSIX标准,我们的开发也会按照标准来进行。

#ifndef _COMS_H_#define _COMS_H_/** * The Struct is for storing the splitting command * the user input and the num of the command and its command * * @params coms The command and its args * @params tnum The nums of command and its args * @author hongbochen * @date 2016-08-26 * */typedef struct com{  char* coms[50];  int tnum;} Com;char* getCom(Com* cm);Com* subCom(char *com);void dealCom(Com* cm);#endif

这里的coms.h用来命令数组,来保存相应的命令以及其参数,同时将该数组的个数也保存到该结构体中。同时定义了几个函数,分别是分割命令函数,处理命令函数,获取命令函数。这里的获取命令函数的意思是:将用户输入的命令和函数进行分割,然后保存到coms数组中,获取命令函数的作用就是获取数组中的第一个元素,即为用户的命令,因为其他的元素都是相应的命令参数。

下面我们来看一下这些函数的实现:

#include "coms.h"#include 
#include
#include
char* getCom(Com* cm){ if(cm->tnum < 1){ return NULL; }else{ return cm->coms[0]; }}/** * 解析用户输入的命令 * @param com 用户输入的命令字符串 * @author hongbochen * @date 2016-08-24 * @note In this version, We just split the string using blank enter code here*/Com* subCom(char *com){ //char* comss[50]; char *token = strtok(com, " "); int nums = 0; // 分配空间 Com* bc = (Com *)malloc(sizeof(Com)); while(token != NULL) { bc->coms[nums] = (char *)malloc(sizeof(char) * 20); strcpy(bc->coms[nums], token); // go to the next token token = strtok(NULL, " "); nums++; } bc->tnum = nums; //return comss; return bc;}/* * 处理被解析出来的命令 * @param cm 解析出来的命令结构 * @author hongbochen * @date 2016-08-26 */void dealCom(Com* cm){ char* fm; if((fm = getCom(cm)) != NULL){ printf("%s\n", fm); }}

这里的实现比较简单,也有相应的注释,处理命令函数还没有完全实现,下一篇文章将会实现。

下面我们看一下比较重要的main函数:

#include 
#include
#include
#include
#include
#include
#include "coms.h"/* Use this to judge whether the program is running or not */int isRun = 1;/* * @author hongbochen * @date 2016-08-24 * @des This is a simple shell. * */int main(int argc,char *argv[]){ /* The prompt of start */ char prompt[200]; /* The command the user input */ char* line; // The variable of this prog int i = 0; /* Run the app in loop */ while(isRun){ getcwd(prompt,sizeof(prompt)); strcat(prompt,"$ "); if(!(line = readline(prompt))) break; /* if(strcmp(line, "exit") == 0){ isRun = 0; }else if(strcmp(line, "echo") == 0){ printf("%s\n", line); } */ // get the split command the user input Com* cms = subCom(line); dealCom(cms); }}

在这里这个函数不在赘述,但是有一个事情数需要说明的是,由于我们使用了readline库,所以在编译之前需要安装readline库,同时在编译的时候,编译指令需要指定readline库。

gcc main.c coms.c -o main -lreadline

下面我们使用./main来运行一下该程序:

这里写图片描述

你可能感兴趣的文章
水晶报表在大型WEB内部管理系统里的滑铁卢
查看>>
我的友情链接
查看>>
Git学习
查看>>
trove 基于 centos7 制作 mysql5.6 镜像
查看>>
结合i节点和数据块分析linux中软链接和硬链接的区别
查看>>
Heartbeat crm的配置
查看>>
Stream
查看>>
我的友情链接
查看>>
Windows Server 2012_Install_Guide
查看>>
ISA Server搭建站点对站点×××
查看>>
我的友情链接
查看>>
超大规模数据中心:给我一个用整机柜的理由先
查看>>
执行命令取出linux中eth0的IP地址
查看>>
CRUD全栈式编程架构之控制器的设计
查看>>
python常用内建模块(五)
查看>>
你为什么有那么多时间写博客?
查看>>
Excel 中使用VBA
查看>>
$.ajax同步请求会阻塞js进程
查看>>
Postman 网络调试工具
查看>>
Python教程6
查看>>