文章目录

  • 前言
  • 功能与展示
    • 功能列表
    • 功能展示
  • 依赖库安装
  • 具体实现
    • Shell工作流程
    • 外部命令工作流程
    • 内置命令工作流程
    • 管道功能与I/O重定向的实现
    • alias功能的一些思考
  • Shell的编译与运行
  • 源码

前言

最近操作系统结课了,不过还有一个课程设计需要完成。可供选择的题目并不少:Shell编程、系统调用、文件系统等等。当时觉得Shell编程看起来很有挑战性,实现后应该会很炫酷,而且课程设计指导上对Shell编程介绍的篇幅也是最大的。老师或许会给这个课题最高的分数? 于是没有太多犹豫就确定了下来。
本以为自己写一个Shell不简单,等到多看了几篇博客理解了其中原理后,才发现要实现一个简单的Shell其实并不困难。它就是对之前操作系统实验的综合运用。
关于如何用c来写一个Shell,网上已经有很多很棒的博客啦。比如山城过雨这位大神写的文章——《myShell:Linux Shell 的简单实现》,写的非常详细,只需要认真阅读一遍就能对整体流程了解地差不多了。我写这篇博客,不会去过多描述相同的内容,而是会记录一些自己做课程设计中的一些心得。

功能与展示

要做什么,标题已经说得很清楚了。那么再展示一下实现的功能吧,是不是你所想要的,一眼便能看明白。

功能列表

  1. 编写一个C语言程序作为Linux内核的shell命令行解释程序,所执行的结果需和系统命令行方式保持一致。
  2. 增加后台运行功能。即用户可以使用”&”作为一个命令结束,以启动下一个命令。
  3. 增加I/O重定向功能。即用户可以使用”<”和”>”符号改变程序/文件的输入和输出。
  4. 增加管道功能。即支持以“|”进行进程间通信操作。
  5. 增加退出功能。输入“exit”命令或者Ctrl +D退出。
  6. 增加文件名替换功能。(课设要求上是这么写的,我理解为mv命令的使用)
  7. 增加命令补全功能。即按下tab键可以补全命令。
  8. 增加查阅历史记录的功能。可以查看历史命令。
  9. 支持目录检索功能。即文件不存在,继续打印提示符。
  10. 支持一定的错误输入处理。例如:多于空格的出现,输入命令不存在,空输入等等。

主要功能就这些,常用的外部命令,ls、cat、cp等,我就不再列出了。其实在课设中还有一个可选实现的功能:alias别名功能。但由于时间有限(一周内要完成两个课设和两门期末考试,承担的还是主要代码工作),所以没能深入研究下去。不过在文末,我会给出自己关于alias功能实现的一些思路以及参考链接。以后有空了再回头研究。

功能展示

简单放几张展示图,分别为帮助功能、查看历史命令功能和I/O重定向功能。Shell提示符模仿的是命令提示符的样式,并在头部加入了红色的Myshell字样用于区分。


依赖库安装

在Shell的编写过程中,需要用到readline库,借此实现tab键代码补全、查看历史命令等功能。当然,readline库的功能远不止于此,如果想深入了解并运用,可以阅读官方文档。
我的虚拟机上安装的系统是Ubuntu 16.04.6 LTS。
redhat系列下这个软件包叫readline-devel,ubuntu下叫readline-dev,细分为libreadline5-dev和libreadline6-dev。但是apt安装时发现,libreadline5-dev已经不存在了,不过libreadline6-dev还是在的,于是可以通过以下命令进行安装:

sudo apt-get install libreadline6-dev

此外,readline库还依赖于一个底层输入输出的库——ncurses,安装命令行如下:

sudo apt-get install libncurses5-dev

到此为止,依赖库的安装配置已经完成。

具体实现

Shell工作流程

Shell的工作流程如下图所示:

其实实现原理很简单,使用while循环持续接收用户命令,根据读入的字符串判断命令类型并进行相应的处理。
接下来,我会以流程图与代码结合的说明工作流程。

外部命令工作流程

外部命令工作流程如下图所示:

以“mv t1 t2”命令为例,首先程序读入用户输入的字符串,存入字符串数组command中。调用analysis_command()函数进行分析:

int i = 1;
char *p;
//分割依据,这里的分割依据为空格
char delims[] = " ";
argc = 1;
//将command字符串中第一个空格以前的字符串存入argv[0],这里是"mv"
strcpy(argv[0],strtok(command,delims));
//继续对剩余字符串进行切分,并将切分结果存入argv数组中
while(p = strtok(NULL,delims)){strcpy(argv[i++],p);argc++;
}
//判断输入的指令是否为内置命令
if(!(strcmp(argv[0],"exit"))||!(strcmp(argv[0],"help"))|| !(strcmp(argv[0],"cd"))||!(strcmp(argv[0],"history"))){BUILTIN_COMMAND = 1;
}
//判断输入的指令是否含有管道功能的符号
int pipe_location;
for(int j = 0;j < argc;j++){if(strcmp(argv[j],"|") == 0){PIPE_COMMAND = 1;pipe_location = j;                break;}
}
...
//中间省略了其他指令的判定及处理
if(PIPE_COMMAND){...
}
...
else{//argvtmp1存储分割后的指令argvtmp1 = malloc(sizeof(char *)*argc+1);int i;    for(i = 0;i < argc + 1;i++){argvtmp1[i] = malloc(sizeof(char)*100);if(i < argc)strcpy(argvtmp1[i],argv[i]);  }//execvp函数中,参数列表的最后一项必须是 NULLargvtmp1[argc] = NULL;
}

得到以空格分割后的指令数组argvtmp1后,调用do_command()函数执行指令:

if(PIPE_COMMAND){...
}
...
else{//调用fork()函数创建子进程,在子进程中执行指令pid_t pid = fork(); if(pid == -1){printf("fork failed !\n");        }else if(pid == 0){//调用execvp()函数执行程序,第一个参数是要运行的程序名,第二个参数是命令行参数列表//若失败则返回值为-1,输出"command not found"的提示if(execvp(argvtmp1[0],argvtmp1) < 0){printf("%s:command not found\n",argvtmp1[0]);         }}else{int pidReturn = wait(NULL); }
}
//释放malloc( )分配的内存
free(argvtmp1);

外部命令执行结束,回到主程序并打印提示符。

内置命令工作流程

内置命令的工作流程如下图所示:

内置命令的工作流程与外部命令的工作流程大同小异,只是多了一步执行对应函数的操作。这个对应函数可以由自己编写,比如help命令:

void builtin_command(){...//判断输入指令是否为"help"if(strcmp(argv[0],"help") == 0){help();}...
}void help(){//打印用户名和内置命令列表struct passwd* pwp;pwp = getpwuid(getuid());printf("Hi, %s !\n",pwp->pw_name);printf("Here are the built-in commands:\n\n");printf("1. cd\n");printf("2. history\n");printf("3. help\n");printf("4. exit\n");
}

也可以调用已有的函数,比如要实现cd指令,就需要用到chdir()函数。

管道功能与I/O重定向的实现

管道功能与I/O重定向的实现,与上面内置命令与外部命令的工作流程没有多大区别,前人之述备矣。读过之后我在Shell中加入了简单的输入重定向,没有遇到太大的问题,就不再赘述了。

alias功能的一些思考

alias不是外部命令,只能调用函数或者自己实现。在网上找了好久有关alias的工作原理,不知是描述不准确还是别的原因,我并没看到描述alias工作原理的相关文章,也没找到某个库是附带alias功能函数的。不过看的多了,也就有了一点自己的想法,先挖个坑记录下来,等以后有时间了再埋。
目前的思路是,在用户主目录下的.bashrc文件中记录存放alias命令的文件名(比如.aliases)。然后于Shell内置命令中添加alias和unalias的指令判定,添加的别名都存入文件.aliases中。(感觉alias的实现原理大致就是如此,但在没有看到某篇文章明确说之前,也不敢下结论)
网上找到的一些博客,或许对你有些帮助:
bash中的alias命令实现(自己实现)
在文件保存alias命令并生效

Shell的编译与运行

readline是动态链接库,gcc时需要加上-lreadline。ncurses作为readline依赖的底层输入输出库,需要放在readline的后面。

gcc MyShell.c -o MyShell -lreadline -lncurses

输入./MyShell即可进入Shell。

源码

Shell源码已经放在Github上,供大家学习和参考。

操作系统课程设计——Shell编程(用c编写一个Linux的外壳Shell)相关推荐

  1. 操作系统课程设计---实验十 简单shell命令行解释器的设计与实现

    实验十 简单shell命令行解释器的设计与实现 完整课程设计源码及其报告查看:陈陈的操作系统课程设计 1.实验目的 本实验主要目的在于进一步学会如何在 Linux 系统下使用进程相关的系统调用,了解 ...

  2. java编写文件系统的方法_操作系统课程设计模拟文件系统Java

    [实例简介] 一个操作系统课程设计,使用java语言模拟磁盘文件系统实现,实现了FAT算法 [实例截图] [核心代码] e692cc3b-c785-40f6-babe-2f9d5383f034 └── ...

  3. HDU操作系统课程设计实验三

    HDU操作系统课程设计实验三 一.设计目的 二.内容要求 三.实验内容 信号量的使用 1.实现一个模拟的shell,基本功能加find.grep命令 2.实现一个管道通信程序,基本功能加有名管道通信 ...

  4. 检索上Linux操作系统课程的教师名,Linux操作系统课程设计.docx

    课 程 设 计 报 告 课程名称 Linux操作系统课程设计 指导教师 起止日期 2016-03-21 至 2016-06-13 学 院 信息与通信工程学院 专 业 电子信息工程 学生姓名 班级/学号 ...

  5. 操作系统课程设计.doc 高分大作业(97分),共25页word版本

    操作系统课程设计 操作系统课程设计.doc 实验列表 实验内容 文档部分截图 关于实验过程截图 文档获取 操作系统课程设计.doc 操作系统课程设计高分大作业(97分),共25页word版本. wor ...

  6. 操作系统课程设计geekos project1-3

    概述 实验环境 GeekOS-0.3.0 Bochs和Vmware介绍 开发过程 编译运行 配置文件 前导知识 一.全局描述符表GDT(Global Descriptor Table) 二.段选择子( ...

  7. linux课程设计死锁避免,linux操作系统课程设计—车辆死锁.doc

    linux操作系统课程设计-车辆死锁.doc 键入文字"操作系统原理"课程设计BX090709吴沛儒操作系统原理课程设计报告姓名吴沛儒班级BX0907学号9指导老师胡静二〇一一年十 ...

  8. 华科计算机课程设计,华中科大操作系统课程设计报告(附源码).doc

    华中科技大学计算机学院 操作系统课程设计报告 班级: 学号: 姓名:彭博 时间:2010年3月 设计内容一:熟悉和理解Linux编程环境 编写一个C程序,实现文件拷贝功能. 2)编写一个C程序,使用下 ...

  9. 华中科技大学计算机课程设计,华中科技大学计算机学院操作系统课程设计资料报告材料[1].doc...

    <华中科技大学计算机学院操作系统课程设计资料报告材料[1].doc>由会员分享,提供在线免费全文阅读可下载,此文档格式为doc,更多相关<华中科技大学计算机学院操作系统课程设计资料报 ...

最新文章

  1. 2020-10-09
  2. 一个例子来使用sklearn中的TfidfVectorizer
  3. 【快乐水题】1716. 计算力扣银行的钱
  4. FileMonitorKit 文件操作监控工具
  5. MyEclipse+Tomcat web项目改名
  6. ionic + cordova 使用 cordova-gallery-api 获取本地相册所有图片
  7. flask同源策略解决办法及flask-cors只允许特定域名跨域
  8. Android源码中的FLAG为何使用16进制
  9. 在集设|参透海报设计中提取排版设计灵感
  10. hdu 1506 单调栈问题
  11. python替换文本文件单词_Python:如何替换文本文件中一行的最后一个单词?
  12. mysql怎么导入sql文件_如何将sql文件导入mysql
  13. 同时带多个文件生成软盘镜像的方法
  14. solid works旋转、抽壳的应用
  15. 薅羊毛的神器,悄悄介绍给你,低调使用!
  16. matlab cdfx,在 Simulink 数据字典中使用 ASAM CDFX 数据
  17. 带你走进API安全的知识海洋
  18. 用MATLAB编写限幅滤波程序,双二阶滤波器之MATLAB设计及C语言实现
  19. 一些小软件闪退的解决方案
  20. linux下socket编程(基础参考)

热门文章

  1. BLDC的三闭环控制
  2. 快速收集资料的一种方法
  3. 谷歌浏览器上传图片或任何文件都卡死
  4. 学习Vue的SSR,这可能是最好的教程
  5. Android中使用x5内核加载网页的实现
  6. 不用心率表,教你一秒钟知道自己的心率
  7. process_vm_readv/writev进程间数据传输
  8. 神经肿瘤组学基础知识、工作流程及应用
  9. 点牛--当FJ点到一头奶牛时,及时提醒他下一头奶牛的编号就可以了。
  10. vue *** is not a function 解决