MIT6.828学习之homework2:shell
之前同学提起,能区分得开xv6与JOS吗?才发现真不知道,赶紧查了查:
1.extended inspection of xv6, a traditional O/S
xv6,一个传统的操作系统的扩展的分析
2.Lab: JOS, a small O/S for x86 in an exokernel style
实验:JOS,为x86平台所写的一个小型的微内核操作系统
3.x86泛指一系列基于Intel 8086且向后兼容的中央处理器指令集架构
谢谢马如风
主要得明白文件描述符、重定向、管道、runcmd()、parsecmd()
作业内容:补全shell代码
什么是shell呢?
Shell 是一个
应用程序
,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核,这就是 Shell的本质。
Shell 程序本身的功能是很弱的,比如文件操作、输入输出、进程管理等都得依赖内核。我们运行一个命令,大部分情况下 Shell都会去调用内核暴露出来的接口(系统调用
),这就是在使用内核,只是这个过程被 Shell 隐藏了起来
谢谢仁兄
xv6 shell的执行流程:
- shell 执行 getcmd 获得用户输入的命令
- shell 执行 fork 创建一个shell进程的copy,然后shell进入wait状态
- shell 执行 runcmd 运行用户的命令
- runcmd函数调用exec系统调用加载适当的函数如:echo
- 在函数(echo) 的结束,有exit系统调用返回shell,shell从wait中退出
谢谢卖萌的弱渣
命令有5类:
执行命令 符号: “ ” 重定向命令 > 或者 < 列表命令,也就是多个命令 符号是分号 ; 管道命令,需要先建立管道 符号是 | 返回命令(这个不知道是干嘛的),符号是 &
整个函数的
核心
函数有两个,一个是parsecmd,一个是runcmd
当读入命令的时候,首先进行解析
parsecmd的核心函数是parseline
这个函数是递归的,执行流程:首先执行parsepipe,检测是否有管道命令,有的话建立管道连接 检测命令中是否有&,也就是返回命令,有的话用parsepipe的返回值生成一个新的backcmd 检测是否有;,也就是是否有多条命令分别要执行,有的话,递归调用parseline,将所有的命令分别解析之后连接起来
谢谢bdhmwz
关键与难点:弄清主要几个函数的意义与用法,尤其是参数的意义。还得懂文件描述符
1.涉及Shell 命令
ls > y 把ls结果输出到文件y中 cat cat命令的用途是连接文件或标准输入并打印。这个命令常用来显示文件内容,或者将几个文件连接起来显示,或者从标准输入读取内容并显示,它常与重定向符号配合使用一次显示整个文件:cat filename从键盘创建一个文件:cat > filename 只能创建新文件,不能编辑已有文件将几个文件合并为一个文件:cat file1 file2 > file uniq uniq命令常用语报告或者消除文件中的重复内容,一般与sort命令结合使用 wc wc命令的功能为统计指定文件中的字节数、字数、行数, 并将统计结果显示输出ls > y cat < y | sort | uniq | wc > y1 功能:把当前目录ls的结果存到y中,然后读取y的内容,然后将y的内容排序,去掉重复,然后统计字数,行数.并把结果保存到y1
什么是Unix Pipeline
举个例子: ls -1 | grep p | more 只列出来还有字母p的当前目录下的文件
Pipeline 使用”|“来区分多个命令,从左到右,前一个命令的结果是后一个命令的输入
谢谢仁兄
2.int execv(const char *progname, char *const argv[]);
execv会停止执行当前的进程,并且以progname应用进程替换被停止执行的进程,进程ID没有改变。
- progname: 被执行的应用程序。
- argv: 传递给应用程序的参数列表, 注意,这个数组的第一个参数应该是应用程序名字本身,并且最后一个参数应该为NULL,不参将多个参数合并为一个参数放入数组。
- 返回值:如果应用程序正常执行完毕,那么execv是永远不会返回的;当execv在调用进程中返回时,那么这个应用程序应该出错了(可能是程序本身没找到,权限不够…), 此时它的返回值应该是
-1
,具体的错误代码可以通过全局变量errno
查看,还可以通过stderr
得到具体的错误描述字符串:
谢谢卖萌的弱渣:
3. extern char strchr(char *str,char character)
从字符串str中寻找字符character第一次出现的位置。参数说明:str为一个字符串的指针,character为一个待查找字符。 所在库名:#include <string.h>
4.open 函数原型:int open(const char *pathname, int flags, mode_t mode);
- flags must include one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR.
- mode: 创建文件时设定的其他用户权限: S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
- 返回值:调用成功时返回一个文件描述符fd;调用失败时返回-1,并修改errno
5.dup 函数原型: int dup(int oldfd);
函数说明: create a copy of the file descriptor oldfd。dup出来的新fd共享之前fd的offset
6.int gettoken(chasr **ps, char *es, char **q, char **eq)
// 把地址ps到es的字符串中的变量找到,并存到q到eq的地址去
7.int peek(char **ps, char *es, char *toks)
//判断从地址ps到es的字符串是否含有toks里面的字符
8.char *mkcopy(char *s, char *es)
// s指向需要拷贝的字符串头,es指向需要拷贝的字符串结尾. 这个函数拷贝从s到es的字符串,然后返回拷贝的地址。
9.struct cmd* parsecmd(char *s)
// 解析命令把buffer里的命令包装成可执行的数据结构struct cmd
其他函数:
int chdir(const char * path);
用户将当前的工作目录改变成以参数路径所指的目录。
char *strcat(char *dest, const char *src)
把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。
char *strerror(int errnum)
从内部数组中搜索错误号 errnum,并返回一个指向错误消息字符串的指针。errnum – 错误号,通常是 errno
,是个整型。
代码补全
case ’ ':
ecmd = (struct execcmd*)cmd;if(ecmd->argv[0] == 0)_exit(0);//The hard part is figuring out what execv and its parameters mean//So that I can modify the pathif(execv(ecmd->argv[0],ecmd->argv)==-1){char mypath[20]="/bin/";strcat(mypath,ecmd->argv[0]);if(execv(mypath,ecmd->argv)==-1){strcpy(mypath,"/usr/bin/");// I write "/user/bin/" and wrong...strcat(mypath, ecmd->argv[0]);if(execv(mypath,ecmd->argv)==-1){fprintf(stderr, "Command %s can't find\n", ecmd->argv[0]);_exit(0);}}}
case ‘<’:
case ‘>’:
rcmd = (struct redircmd*)cmd;close(rcmd->fd);if(open(rcmd->file, rcmd->flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)<0){fprintf(stderr, "file %s can't find\n", rcmd->file);_exit(0);}runcmd(rcmd->cmd);break;
case ‘|’:
最难的最有用的就是管道命令了,可以很深刻的理解文件描述符,也能非常好的明白文件重定向
文件描述符是一个int型数,它就像一个文件的索引一样,或者是一个文件指针。按我的理解,每个文件都会有一个自己的fd
,用于被其他文件使用,还会有一张fd表
,用于记录与其他文件的关系
谢谢 sky_Mata的图以及介绍
这位大哥说的很好,图也很清晰,但是我还是不明白怎么写完这个管道命令,于是我又读了别人的代码,画出了我的理解:
于是我写出了这段代码
pcmd = (struct pipecmd*)cmd;//fprintf(stderr, "pipe not implemented\n");// Your code here ...if(pipe(p)<0){fprintf(stderr,"Fail to create a pipe\n");_exit(0);}if(fork1()==0){//child one:read from stdin(0), write to the right end of pipe(p[1])close(1);dup(p[1]);close(p[0]);close(p[1]);runcmd(pcmd->left);}if(fork1()==0){//child two:read from the left end of pipe(p[0]), write to stdout(1)close(0);dup(p[0]);close(p[0]);close(p[1]);runcmd(pcmd->right);}close(p[0]);close(p[1]);wait(&r); //the position of wait I have a little confusionwait(&r);break;
自问自答
1.为什么我又没有写ls,cat,却可以exec它们,它们就是系统调用接口吗?
答:我认为这些是linux封装好的命令,不是系统调用,但是它们会调用很多系统调用来实现自己的功能。
2.为什么明明cmd结构体只有个type,赋值给其他结构体redircmd、execcmd等却可以把其他参数补全?
答:我认为在main()函数中的runcmd(parsecmd(buf))中,执行parsecmd后就已经根据cmd->type参数返回了相对应的结构体类型,通过struct cmd *这种基类
结构体指针来存是个很聪明的选择
3.分析命令的过程还得仔细弄清楚!如“echo “6.828 is cool” > x.txt"从输入到运行下来,是怎么样的?
首先getcmd,将整条命令存到buf里,buf=“echo “6.828 is cool” > x.txt”
然后判断是不是cd命令,这里不是
然后fork1创建一个子进程,子进程里通过parsecmd将buf解析赋值给execcmd结构体
最后执行runcmd(cmd)
(其实parsecmd内部具体怎么搞得我还是比较模糊)
4.fork?
fork就是当前进程创建一个子进程,然后父进程等待子进程的执行。
子进程和父进程有着相同的文件描述符,数据也相同,只是存储的内存不同。
fork在子进程和父进程中都会有返回值,在父进程中返回子进程的pid,子进程中返回0。
5.每执行一条命令都会开辟一个进程吗?
答:不是吧,得fork才会创建新进程。main函数中fork了,管道命令中fork了两次。
6.parseredir在哪里引用了?
答:终于找到了,在parseexec()函数里的第八行处用到了
主要参考
用到的函数介绍
详细介绍
chapter 0介绍
关于管道的介绍
MIT6.828学习之homework2:shell相关推荐
- MIT6.828学习之Lab1
一.概要 了解x86汇编语言,学会用QEMU模拟x86环境,学会用GDB调试 BIOS负责执行基本的系统初始化,从某些适当的位置(如 floppy disk(软盘), hard disk, CD-RO ...
- MIT6.828学习之homework9:Barriers
在本作业中,我们将探讨如何使用pthread库提供的条件变量来实现barrier.barrier是应用程序中的一个点,在这个点上,所有线程都必须等待,直到所有其他线程也到达该点.条件变量是一种序列协调 ...
- MIT6.828课程学习初步
MIT6.828课程学习初步 MIT6.828课程是1门比较好的操作系统原理课程,通过动手实践xv6操作系统来熟悉原理. [ 课程网站 ] 原先是想从Linux内核开始看起,但是看了一段时间,由于都是 ...
- Mit6.S081学习记录
Mit6.S081学习记录 前言 一.课程简述 二.课程资源 1,课程主页 2,参考书 3,实验环境 三.学习过程 Mit6.S081-实验环境搭建 Mit6.S081-GDB使用 Mit6.S081 ...
- MIT6.828课程JOS在macOS下的环境配置
本文将介绍如何在macOS下配置MIT6.828 JOS实验的环境. 写JOS之前,在网上搜寻JOS的开发环境,很多博客和文章都提到"不是32位linux就不好配置,会浪费大量时间在配置环境 ...
- MIT6.828——LAB1:Booting a PC
MIT6.828--LAB1:Booting a PC Part1:PC Bootstrap 练习1: 熟悉X86汇编语言 The PC's Physical Address Space 电脑的物理地 ...
- Nginx学习笔记3:Shell脚本检测Nginx服务状态
前言 nginx 服务启动后,我们需要对其服务状态进行监控,今天学习过程中了解到一段非常有用的小脚本,不仅可以监控Nginx,也可以用来监控其他服务 脚本 A=`ps -C nginx –no-hea ...
- 史上最牛最强的linux学习笔记 10.shell基础
史上最牛最强的linux学习笔记 10.shell基础 写在最前面: 本文是基于某站的视频学习所得,第一个链接如下: https://www.bilibili.com/video/BV1mW411i7 ...
- MIT6.828 32位操作系统笔记(3)----系统的启动和初始化
MIT EDU 6.828 实验源代码 分类 MIT6.828 32位操作系统实验笔记 实验完善代码 LAB2-4下载链接 提取码:79t8 系统的启动过程 物理内存的分布 首先分析PC 开机以后的默 ...
最新文章
- SpringDataRedis对Redis的数据类型的常用操作API的使用代码举例
- 2016-04-29 二分查找的面试题
- Cracer渗透-windows基础(系统目录,服务,端口,注册表)
- 让Team Foundation Server/TFS自动记住用户名密码解决方案
- 智慧交通day03-车道线检测实现02-1:相机校正
- word图片填充之后图片颜色变灰了_一文读懂如何快速实现网页页面变灰?
- 专业测试工程师浅谈功能测试用例模板设计
- 计算机二级access数据库考试题型,2016最新计算机二级Access数据库试题及答案
- python求方程的根_python计算方程式根的方法
- 用excel将有规律的数据随机打乱
- 重置网络命令win7
- mysql 建复合索引_mysql 建立复合索引
- android格式化SD卡,获取其它程序的缓存大小,清理数据
- redis多实例常见部署方法和使用
- 条形码入门指南(八):二维条形码
- Python(Tuirtle库)简单动画--升旗
- mysql及格率70以上_五个 SQL 查询性能测试题,只有 40% 及格率,你敢来挑战吗?| 原力计划...
- 华为系大数据专家傅一航老师--沪师经纪刘建
- D. Vessels(并查集+模拟)
- 国内首家中外合资人寿保险公司--中宏保险获批筹建陕西分公司
热门文章
- 7. 重磅硬核 | 一文聊透对象在JVM中的内存布局,以及内存对齐和压缩指针的原理及应用
- 2018-12-22-jekyll-theme-H2O
- 电大考试计算机应用基础考试试题,电大计算机应用基础网络教育统考考试(2013真题卷)...
- 数仓可视化,低代码开发平台
- 人生百味-10:顺势而为(外圆)与自我坚持(内方)
- 【手拉手 带你准备电赛】解答小课堂——为什么要使能时钟
- java工程师怎么找兼职,快来看鸭~
- Android真香系列,再也不用数据线就能真机调试啦
- 产品经理是做什么的?
- centos7加载磁盘