实现shell实例

程序主框架

主程序很简单,它在做一些必要的初始化工作之后,进入这样一个循环:

u       打印提示符并等待用户输入

u       获取用户输入

u       分析用户输入

u       解释执行;

如果用户输入 logout或者 exit 之后,才退出这个循环。

用类似伪代码的形式表示如下:

while(1) {

print_prompt();

get_input();

parse_input();

if(“logout” || “exit”)

break;

do_cmd();

}

读取用户输入

如何获取用户输入?一种方法是通过 getchar() 从标准输入每次读一个字符,如果读到的字符是 ‘\n’,说明用户键入了回车键,那么就把此前读到的字符串作为用户输入的命令。

代码如下:

int len = 0;

int ch;

char buf[300];

ch = getchar();

while(len < BUFSIZ && ch != '\n') {

buf[len++] = ch;

ch = getchar();

}

if(len == BUFSIZ) {

printf("command is too long\n");

break;

}

buf[len] = '\n';

len++;

buf[len] = 0;

但是,我们注意到,在 bash 中,可以用“<-”和“->”键在命令行中左右移动,可以用上下键调用以前使用的命令,可以用退格键来删除一个字符,还可以用 tab 键来进行命令行补全。我们的shell如果也要支持这些功能,那么就必须对这些键进行处理。这样仅仅对用户输入的读取就非常麻烦了。

实际上,任何需要一个获取用户输入的程序,都会涉及到同样的问题,如何象bash 那样处理键盘?GNU readline 库就是专门解决这个问题的,它把对键盘的操作完全封装起来,对外只提供一个简单的调用接口。有了它,对键盘的处理就不再让人头疼了。

关于 readline 库的详细信息,可以通过 man readline 来看它的帮助页面。在我们的 shell 程序中,我是这样来使用 readline的。

char* line;

char prompt[200];

while(1) {

set_prompt(prompt);

if(!(line = readline(prompt)))

break;

。。。。。。

}

首先通过 set_prompt() 来设置要输出的提示符,然后以提示符作为参数调用 readline(),这个函数等待用户输入,并动态创建一块内存来保存用户输入的数据,可以通过返回的指针 line 得到这块内存。在每次处理完用户输入的命令之后,我们必须自己负责来释放这块内存。

有了 readline 之后,我们就可以象 bash 那样使用键盘了。

在通过 readline 获取用户输入之后,下一步就是对用户输入的命令进行分析。

命令行分析

对命令行的分析,实际上是一个词法分析过程。学过编译原理的朋友,都听说过 lex 和yacc 的大名,它们分别是词法分析和语法分析工具。Lex 和 yacc 都有GNU的版本(open source 的思想实在是太伟大了,什么好东东都有免费的用),分别是 flex 和 bison。

所谓“工欲善其事,必先利其器”,既然有这么好的工具,那我们就不必辛辛苦苦自己进行词法分析了。对,我们要用 lex 来完成枯燥的命令行词法分析工作。

“去买本《lex与yacc》(中国电力出版社)来看吧。第一次学当然稍微有点难度,不过一旦掌握了,以后再碰到类似问题,就可以多一个利器,可以节省劳动力了。

在我们的这个 shell 程序中,用 flex 来完成词法分析工作。相对语法分析来说,词法分析要简单的多。由于我们只是做一个简单的 shell,因此并没有用到语法分析,而实际上在 bash 的实现代码中,就用到了语法分析和 yacc。

关于 lex 的细节,在这里我就不能多说了。Lex程序,通常分为三个部分,其中进行语法分析工作的就是它的第二部分: “规则”。规则定义了在词法分析过程中,遇到什么样的情况,应该如何处理。

词法分析的思路,就是根据前面定义的“shell语法规范”来把用户输入的命令行拆解成

首先,我们要把用户输入的命令,以空白字符(tab键或者空格)分隔成一个个的参数,并把这些参数保存到一个参数数组中。但是,这其中有几种特殊情况。

一、如果遇到的字符是;”、“>”、“<”或“|,由于这些符号是管道或者列表中所用到的分隔符,因此必须把它们当作一个单独的参数。

二、以双引号(括起来的字符串要作为一个单独的参数,即使其中出现了空白字符、“;”、“>”、“<”、“|”。其实,在POSIX标准中,对引号的处理相当复杂,不仅包括双引号(”),还有单引号(’)、反引号(`),在什么情况下,应该用什么样的引号以及对引号中的字符串应该如何解释,都有一大堆的条款。我们这里只是处理一种极简单的情况。

其次,如果我们遇到换行符(’\n’),那么就结束本次命令行分析。根据前面定义的 shell 语法规范,最上层的是列表命令,因此下一步是把所有的参数作为一个列表命令来处理。

转载于:https://www.cnblogs.com/aoogur/archive/2008/12/05/1348723.html

编写自己的Shell解释器-3[转]相关推荐

  1. 体会Linux与生俱来的美 高级篇 编写自己的Shell解释器(全文)

    http://www.csdn.net/subject/linux/shell.mht 编写自己的Shell解释器 摘要:本期的目的是向大家介绍shell的概念和基本原理,并且在此基础上动手做一个简单 ...

  2. 编写自己的Shell解释器

    摘要:本期的目的是向大家介绍shell的概念和基本原理,并且在此基础上动手做一个简单shell解释器.同时,还将就用到的一些 linux环境编程的知识做一定讲解. 本文适合的读者对象 对linux环境 ...

  3. linux(1)- 简单的 shell 解释器

    真正了不起的程序员对自己程序的每一个字节都了如指掌.       计算机科学领域中,没有什么问题是增加一个中间层解决不了的. 目录 做一个简单的 Shell 解释器 环境 思路 具体实现目标 方法 完 ...

  4. 4-1:shell编程之编写第一个shell脚本

    文章目录 一:什么是shell脚本 二:如何编写shell脚本 (1)脚本文件的格式 (2)可执行权限 (3)执行脚本 三:第一个shell脚本 (1)基本结构 (2)变量和常量 A:创建变量和常量 ...

  5. Shell-基础(一):Shell解释器、Shell脚本

    二.Shell解释器 1. Shell解析器种类 Linux提供的Shell解析器有以下几种(linux是开源的,不同的人写了不同风格的解释器): /bin/sh(UNIX默认的shell,已经被/b ...

  6. 几种常见shell解释器(sh,bash,csh,tcsh,ash)以及bash的优点

    文章目录 shell解释器的定义 shell的分类 sh csh tcsh ash bash bash 的优点 shell解释器的定义 Unix/Linux上常见的Shell脚本解释器有bash.sh ...

  7. 刘启成_编写并使用shell脚本

    编写并使用shell脚本 实验环境: 为了集中查看linux服务器各方面的运行情况,管理员(root)希望定制自己的登录环境,以便自动显示监控信息.另外,通过编写简单的shell脚本,熟悉linux自 ...

  8. 在linux中编写shell脚本文件,如何编写简单的Shell脚本(Script)文件之Linux的基本操作...

    如何编写简单的Shell脚本(Script)文件之Linux的基本操作 新建一个文本文件包含所需要的脚本.举例,我会使用pico编辑器写一个脚本用来运行程序tar,带上必要的可选项可以用来解压从因特网 ...

  9. 编写可靠Linux shell脚本的建议

    编写可靠Linux shell脚本的八个建议https://yangxx.net/archives/949 1. 指定bash shell 脚本的第一行,#!之后应该是什么? 如果拿这个问题去问别人, ...

最新文章

  1. x位全排列(next_permutation)
  2. FPGA控制的数码显示电路
  3. mybatis select语句会默认带排序吗_MyBatis中#和$的区别详解
  4. Android生存指南:解Bug策略和思路
  5. 招募 | 清华大学计算机系副教授黄民烈招募NLP方向博士后
  6. 【栈】【856. 括号的分数】【中等】(需回顾)
  7. java 打包 根目录_java – Maven在jar文件的根目录中打包图像
  8. TexStudio编译报错“Critical Package xeCJK Error: The xeCJK package requires XeTeX to function. ..._criti”
  9. 大道至简——软件工程实践者的思想 读后感3
  10. 哈理工计算机学院学生会技术部,计算机与信息学院学生会简介
  11. stm32如何设置蜂鸣器温度报警_有人喊冷?有人喊热?列车空调温度到底如何设置...
  12. 【读书笔记《Android游戏编程之从零开始》】8.Android 游戏开发常用的系统控件(系统控件常见问题)
  13. 关于扫描枪输入英文乱码问题
  14. mysql中分层查询_在mysql中连接任意数量的字符串行(分层查询)
  15. 《算法谜题》-第二章 谜题
  16. 基于单片机的智能照明灯系统
  17. 设置WINRE的硬盘启动
  18. Win11系统电脑硬盘分区方法教程
  19. NOI的1.5.39与7无关的数
  20. IDC:英国脱欧对本国IT支出带来3大潜在影响

热门文章

  1. pythonsys用法_Python中 sys.argv[]的用法简明解释
  2. 中国大学mooc慕课python答案_中国大学MOOC(慕课)Python编程基础题目答案
  3. python中options设置_如何在AngularJS的ng-options中设置value属性?
  4. python调用系统api_Python调用系统底层API播放wav文件的方法
  5. Dancing Link讲解
  6. Luogu P5244 [USACO2019Feb Platinum] Mowing Mischief (动态规划、决策单调性)
  7. BZOJ 4221 [JOI2012春季合宿]Kangaroo (DP)
  8. BZOJ 4814 Luogu P3699 [CQOI2017]小Q的草稿 (计算几何、扫描线、set)
  9. luogu P4238 多项式求逆 (模板题、FFT)
  10. mysql join null_Mysql Join语法以及性能优化