如何写一个简单的shell
如何写一个简单的shell
看完《UNIX环境高级编程》后我就一直想写一个简单的shell来作为练习,因为有事断断续续的写了好几个月,如今写了差不多来总结一下。
源代码放在了Github: https://github.com/Broglie/Oh-Shell
简单的分析
我们的shell不像bash那样复杂全面,只是实现其中的一小部分功能:命令历史,命令补全,支持IO重定向和管道。一共分成几个部分:主
函数文件,输出出错信息,解析命令等。
我们打开bash对照着做,首先bash有命令提示符,我们要做的和bash的命令提示符一样。然后我们读取用户输入的命令并使用readline库
将命令添加到历史命令列表。然后我们将命令传递给解析命令函数,解析命令并执行。
输出命令提示符
打开bash后我们看到初始的命令提示符如下图所示:

以root登录后用cd命令切换到别的工作目录后如下图所示:

我们发现bash的命令提示符格式为[用户名]@[主机名]:[当前工作目录][$或#]。可以看出用户的home目录以~表示,而结尾部分的$或#是
指如果当前用户是普通用户,则命令提示符是$;如果当前用户是root用户,则命令提示符为#。
那么该如何实现呢?我们用getpwuid函数获取用户的信息,包括用户名和用户ID;用gethostname函数获取主机名;用getcwd函数获
取当前用户的当前工作目录。有了用户ID我们就能判断当前用户是不是root,因为root用户的用户ID为0。有了当前工作目录我们就能判断
工作目录是不是在用户的home目录下,如果在home目录下我们就将home目录的部分替换成~。这样打印提示符的任务就完成了,此部分代码
的实现在main.c文件中的getPrompt函数中。
命令历史和命令补全
Linux默认保存最后输入的500个命令历史。我们可以用GNU的readline库实现命令历史和命令补全。安装就按其中的说明的步骤进
行就行。readline的库有很多功能,但我们只需要其中的readline函数和add_history函数就行了。readline函数以一个字符串为参
数作为提示符,返回用户输入的一行命令;add_history函数以一个字符串作为参数,并将此字符串添加到历史命令列表里。
打印出错消息
在err.h头文件中声明了3个错误处理函数:err_ret函数打印出错消息并返回,err_quit和err_sys函数打印出错消息并退出程序。其
后两个函数在发生致命错误时调用,而err_ret函数在发生非致命错误时调用。其实现在err.c文件中。其实现是参照《UNIX环境高级编程》
中的出错处理函数。
实现IO重定向和管道
处理诸如cat < in.data | grep str | sort > out.data这样的命令需要实现IO重定向和管道。默认情况下在shell中运行的程序其标准输
入(描述符为0)和标准输出(描述符为1)都关联到终端,IO重定向是指将程序的标准输入和标准输出重定向到文件或其他设备。shell从描
述符0读,从描述符1写。如果我们想将标准输入重定向就得关闭描述符0,再将其他文件或设备关联到描述符0。对于标准输出也一样。
管道是将进程的标准输入和/或标准输出通过一个数据通道与另一个进程关联。以本节开头的那个例子来说,grep的标准输入来自cat程
序的输出,标准输出则作为sort程序的标准输入。我们可以用pipe函数创建一个管道,其参数是一个int型数组(假设为fd[2]),数组有
两个元素。经由数组返回两个文件描述符,fd[0]为读而打开,fd[1]为写而打开。fd[1]的输出是fd[0]的输入。如果想重定向标准输入,则将
标准输入与fd[0]相关联,如果想重定向标准输出,则将标准输出与fd[1]相关联。
命令解析
我认为命令解析是这个程序中最难的部分了,可能是我没学过编译原理的原因。所以我死扣了好长时间还是不会怎样解析shll命令(现在也没
搞通)。我偶然发现在xv6课程主页上有一个homework是关于这个的,它给出了解析命令的框架,将关键的部分空出来
让学生补全,所以我就照搬出来用了。所以实现的功能也有限,还有命令列表和后台命令不会解析。等以后我看了编译原理后再把这个坑填了。
总结
这个shell虽然简单,但也让我学到了很多知识,查了很多资料。看完《UNIX环境高级编程》后收获了很多,最高兴的莫过于将学到的知识用在
实际的程序中。就写到这里吧。
Reference:
《UNIX环境高级编程 第三版》
xv6: https://pdos.csail.mit.edu/6.828/2014/xv6.html
如何写一个简单的shell的更多相关文章
- UNIX-LINUX编程实践教程->第八章->实例代码注解->写一个简单的shell
一 分析 要实现一个shell,需包含3个步骤 1)读入指令 2)指令解析 3)执行指令 1 从键盘读入指令 从键盘读入指令的几个要点: 1)调用getc函数等待并获取用户键盘输入. 2)每一行命令的 ...
- 自动化运维:(3)写一个简单的Shell脚本(案例)
一.需求 1.test.sh 脚本执行时候需要添加参数才能执行 参数和功能详情如下: 参数 执行效果 start 启动中... stop 关闭中... restart 重启中... * 脚本帮助信息. ...
- 写一个简单的 Linux Shell (C++)
这里可以找到代码 github.com/z0gSh1u/expshell 支持的特性 单条指令的执行 引号引起的参数(如 $ some_program "hello, world" ...
- 一步一步写一个简单通用的makefile(三)
上一篇一步一步写一个简单通用的makefile(二) 里面的makefile 实现对通用的代码进行编译,这一章我将会对上一次的makefile 进行进一步的优化. 优化后的makefile: #Hel ...
- Linux系统学习笔记之 1 一个简单的shell程序
不看笔记,长时间不用自己都忘了,还是得经常看看笔记啊. 一个简单的shell程序 shell结构 1.#!指定执行脚本的shell 2.#注释行 3.命令和控制结构 创建shell程序的步骤 第一步: ...
- 单片机裸机下写一个自己的shell调试器
该文章是针对于串口通讯过程中快速定义命令而写的,算是我自己的一个通用化的平台,专门用来进行串口调试用,莫要取笑 要处理串口数据首先是要对单片机的串口中断进行处理,我的方法是正确的命令必须要在命令的结尾 ...
- python定义的一个简单的shell函数的代码
把写代码过程中经常用到的一些代码段做个记录,如下代码段是关于python定义的一个简单的shell函数的代码. pipe = subprocess.Popen(cmd, stdout=subproce ...
- linux设备驱动第三篇:写一个简单的字符设备驱动
在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动.本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分 ...
- 用Python写一个简单的Web框架
一.概述 二.从demo_app开始 三.WSGI中的application 四.区分URL 五.重构 1.正则匹配URL 2.DRY 3.抽象出框架 六.参考 一.概述 在Python中,WSGI( ...
随机推荐
- 工程中建立多个src目录
android 工程下可以有多个源代码的目录,不一定都要放到src下面.可以在 .classpath 文件中添加. 默认是这样的: <classpath> <classpathent ...
- Sqlite小数作差,会减不尽?
select 6307.65-5922.68 from CW_ZWMX 以上语句,在设Navigate中执行的结果是:384.969999999999 不解!!!
- .net网站发布到局域网流程
将.net网站发布到局域网的服务器上,会遇到一些版本问题,下面把发布的流程简单说一下 一:发布网站 1.首先把需要的引用程序集都重新生成一下 2.程序集都重新生成之后,右击网站项目,选择发布选项 3. ...
- 打造H5里的“3D全景漫游”秘籍
近来风生水起的VR虚拟现实技术,抽空想起年初完成的“星球计划”项目,总结篇文章与各位分享一下制作基于Html5的3D全景漫游秘籍. QQ物联与深圳市天文台合作,在手Q“发现新设备”-“公共设备”里,连 ...
- strace命令简单用法
strace可以显示一个程序经历的系统调用,接收到的信号等信息. 用法: 1.strace -ff -o output programName 将程序programName的写入output文件中,- ...
- Unity UI on the HoloLens
Following the steps under "Required configuration" will allow Unity UI to continue to work ...
- 学习C++的第三天
1.sort函数(默认升序排序(从小到大)) 要使用此函数只需用#include <algorithm> sort即可使用,语法描述为: sort(begin,end),表示一个 ...
- jquery 获取一组元素的选中项 - 函数、jquery获取复选框值、jquery获取单选按钮值
做表单提交时,如果现在还在用form提交,用户体验很差,所以一般使用ajax提交. 其中需要获取每个表单输入元素的值,获取的时候像文本框这些还好说,Jquery提供了 .val() 方法,获取很方便, ...
- asp.net中插件开发模式说明
第一定义接口 /// <summary> /// 这是插件必须实现的接口,也是主程序与插件通信的唯一接口 /// 换句话说,主程序只认识插件里的这些方法 ...
- 【转载】快速收索并更新sid 方法
利用Google的搜索功能,可以获得不少SAS各个版本的SID号,试过之后你会异常惊喜.1.打开谷歌: http://google.com.hk2.输入或复制这个段文字:"SID_heade ...