课后实践之mybash20155314
课后实践之mybash
实践要求
加分题-mybash的实现
- 使用fork,exec,wait实现mybash
- 写出伪代码,产品代码和测试代码
- 发表知识理解,实现过程和问题解决的博客(包含代码托管链接)
预备知识
关于bash
- Bash (GNU Bourne-Again Shell) 是大多数Linux系统以及Mac OS X默认的shell,它能运行于大多数类Unix风格的操作系统之上,甚至被移植到了Microsoft Windows上的Cygwin系统中,以实现Windows的POSIX虚拟接口。此外,它也被DJGPP项目移植到了MS-DOS上。
- bash的命令语法是Bourne shell命令语法的超集。数量庞大的Bourne shell脚本大多不经修改即可以在bash中执行,只有使用了Bourne的特殊变量或内置命令的脚本才需要修改。 bash的命令语法很多来自Korn shell (ksh) 和 C shell (csh), 例如命令行编辑,命令历史,目录栈,$RANDOM 和 $PPID 变量,以及POSIX的命令置换语法: $(...)。作为一个交互式的shell,按下TAB键即可自动补全已部分输入的程序名、文件名、变量名等等。
操作系统的核心
- 文件:字节序列
- 虚拟内存:字节数组,抽象出外设和主存
- 进程:操作系统对一个正在运行的程序的一种抽象
操作系统的功能
“管家婆”:管理各种硬件资源
“服务生” :提供接口
-->为用户提供shell(写代码)
-->为程序猿提供系统调用
关于进程

- 进程的状态:
- 创建(created)
- 执行(running)
- 就绪(ready)
- 阻塞(blocked)
- 终止(terminated)
- 进程的状态:
实践过程
准备工作
查询相关命令
用
man -k process命令查看与进程(process)相关的命令,发现有很多很多:

再用
man -k process | grep 2命令进一步查看与系统调用相关的命令(参数2表示与系统调用有关),找到fork和wait命令:

其描述为:fork(2) - create a child process
即fork命令用来创建一个子进程。
wait(2),wait3(2),wait4(2),waitpid(2) - wait for process termination
即wait命令用来等待进程结束。
(后来发现只需查找与创建(create)进程相关的命令
man -k process | grep 2 | grep create就可一步到位,快速找到fork命令:
)用
man -k execute | grep 2命令找到execve命令:

其描述为:execve(2) - execute a file
即execve命令用来执行文件。
模块分析:
exec1.c:
#include <stdio.h>
#include <unistd.h> int main() {
char *arglist[3]; arglist[0] = "ls";
arglist[1] = "-l";
arglist[2] = 0;//NULL
printf("* * * About to exec ls -l\n");
execvp("ls", arglist);
printf("* * * ls is done. bye"); return 0;
}
- 功能:
调用execvp()函数,用man命令查看该函数的用法为:
exec函数会将当前的进程替换为一个新的进程,这个新的进程可以由路径或者文件参数指定。 - 运行结果:

- 功能:
psh1.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> #define MAXARGS 20
#define ARGLEN 100 int execute(char *arglist[]) {
execvp(arglist[0], arglist);
perror("execvp failed");
exit(1);
} char *makestring(char *buf) {
char *cp; buf[strlen(buf) - 1] = '\0';
cp = malloc(strlen(buf) + 1);
if (cp == NULL) {
fprintf(stderr, "no memory\n");
exit(1);
}
strcpy(cp, buf);
return cp;
} int main() {
char *arglist[MAXARGS + 1];
int numargs;
char argbuf[ARGLEN]; numargs = 0;
while (numargs < MAXARGS) {
printf("Arg[%d]? ", numargs);
if (fgets(argbuf, ARGLEN, stdin) && *argbuf != '\n')
arglist[numargs++] = makestring(argbuf);
else {
if (numargs > 0) {
arglist[numargs] = NULL;
execute(arglist);
numargs = 0;
}
}
}
return 0;
}
- 功能:一次性bash。
- 运行结果:

forkdemo1.c:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h> int main() {
int ret_from_fork, mypid;
mypid = getpid();
printf("Before: my pid is %d\n", mypid);
ret_from_fork = fork();
sleep(1);
printf("After: my pid is %d, fork() said %d\n", getpid(), ret_from_fork); return 0;
}
- 功能:即fork的功能,除pid之外复制(duplicate)出一个一模一样的子进程,如同克隆。
- 运行结果:

forkdemo2.c:
#include <stdio.h>
#include <unistd.h> int main() {
printf("before:my pid is %d\n", getpid());
fork();
fork();
printf("after:my pid is %d\n", getpid()); return 0;
}
- 功能:调用2次fork会出现4个after,调用n次fork会出现2^n个after。
- 运行结果:

forkdemo3.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int main() {
int fork_rv; printf("Before: my pid is %d\n", getpid()); fork_rv = fork(); /* create new process */ if (fork_rv == -1) /* check for error */
perror("fork");
else if (fork_rv == 0) {
printf("I am the child. my pid=%d\n", getpid()); exit(0);
} else {
printf("I am the parent. my child is %d\n", fork_rv);
exit(0);
} return 0;
}
- 功能:通过
fork()的返回值来区分是父进程还是子进程:如果返回一个大于0的数(子进程的Pid)则为父进程;如果返回值为0则为子进程;如果返回值为负值则出错。 - 运行结果:

- 功能:通过
forkgdb.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int gi = 0; int main() {
int li = 0;
static int si = 0;
int i = 0; pid_t pid = fork();
if (pid == -1) {
exit(-1);
} else if (pid == 0) {
for (i = 0; i < 5; i++) {
printf("child li:%d\n", li++);
sleep(1);
printf("child gi:%d\n", gi++);
printf("child si:%d\n", si++);
}
exit(0); } else {
for (i = 0; i < 5; i++) {
printf("parent li:%d\n", li++);
printf("parent gi:%d\n", gi++);
sleep(1);
printf("parent si:%d\n", si++);
}
exit(0); }
return 0;
}
相关函数:
getpid():获得自己的pidgetppid():获得父进程的pidsleep():延迟指定数量的时间(作为函数参数,单位为s)
运行结果:

waitdemo1.c:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h> #define DELAY 4 void child_code(int delay) {
printf("child %d here. will sleep for %d seconds\n", getpid(), delay);
sleep(delay);
printf("child done. about to exit\n");
exit(17);
} void parent_code(int childpid) {
int wait_rv = 0; /* return value from wait() */
wait_rv = wait(NULL);
printf("done waiting for %d. Wait returned: %d\n",
childpid, wait_rv);
} int main() {
int newpid;
printf("before: mypid is %d\n", getpid());
if ((newpid = fork()) == -1)
perror("fork");
else if (newpid == 0)
child_code(DELAY);
else
parent_code(newpid); return 0;
}
运行结果:

waitdemo2.c:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h> #define DELAY 10 void child_code(int delay) {
printf("child %d here. will sleep for %d seconds\n", getpid(), delay);
sleep(delay);
printf("child done. about to exit\n");
exit(27);
} void parent_code(int childpid) {
int wait_rv;
int child_status;
int high_8, low_7, bit_7; wait_rv = wait(&child_status);
printf("done waiting for %d. Wait returned: %d\n", childpid, wait_rv); high_8 = child_status >> 8; /* 1111 1111 0000 0000 */
low_7 = child_status & 0x7F; /* 0000 0000 0111 1111 */
bit_7 = child_status & 0x80; /* 0000 0000 1000 0000 */
printf("status: exit=%d, sig=%d, core=%d\n", high_8, low_7, bit_7);
} int main() {
int newpid; printf("before: mypid is %d\n", getpid()); if ((newpid = fork()) == -1)
perror("fork");
else if (newpid == 0)
child_code(DELAY);
else
parent_code(newpid);
}
- 运行结果:

- 运行结果:
伪代码
mybash:for
{
用户输入命令;
fork;
spid:父进程
子进程:exec
}
我的代码
mybash20155314.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define MAXARGS 20
#define ARGLEN 100
int mybash20155314(char *arglist[])
{
int pc,pr;
pc=fork();
pr=wait(NULL);
if(pc==0) execute(arglist);
else return 0;
}
int execute(char *arglist[])
{
execvp(arglist[0],arglist);
perror("execvp failed");
exit(1);
}
char *makestring(char *buf)
{
char *cp;
buf[strlen(buf)-1] = '\0';
cp = malloc( strlen(buf)+1 );
if ( cp == NULL ){
fprintf(stderr,"no memory\n");
exit(1);
}
strcpy(cp, buf);
return cp;
}
int main() {
char *arglist[MAXARGS + 1];
int numargs;
char argbuf[ARGLEN];
numargs = 0;
while (numargs < MAXARGS) {
printf("Arg[%d]? ", numargs);
if (fgets(argbuf, ARGLEN, stdin) && *argbuf != '\n')
arglist[numargs++] = makestring(argbuf);
else {
if (numargs > 0) {
arglist[numargs] = NULL;
mybash20155314(arglist);
numargs = 0;
}
}
}
return 0;
}
运行结果

代码调试过程中遇到的问题
macOS High Sierra下终端man命令中文显示问题

解决方法

参考资料
- MAC下常用命令的中文帮助文档(man)
- MAC下常用命令的中文帮助文档(man) 出现错误
- 用vi修改文件,保存文件时,提示“readonly option is set”的解决方法
- linux 打造man中文帮助手册图解(man-pages-zh帮助页)
- [Mac入门]如何在Mac下显示Finder中的所有文件
- Linux 进程与信号的概念和操作 linux process and signals
课后实践之mybash20155314的更多相关文章
- 第3周课后实践·程序阅读(4)-利用引用訪问私有数据成员
/* * Copyright (c) 2015, 烟台大学计算机学院 * All rights reserved. * 文件名:test.cpp * 作 者:刘畅 * 完毕日期:2015年 3 月 2 ...
- 小垃圾myl的课后实践
#include<iostream> #include<cstdio> using namespace std; int main(){ ,flag=; printf(&quo ...
- 00java语法基础和课后实践
一:运行代码,并分析结果 代码1: package reserve; public class Main { public static void main(String[] args) { Size ...
- 零基础python入门(1)
1.前景及准备 (1).python是一门简单易学且功能强大的编程语言.它拥有高效的高级数据结构,并且能用简单而又高效的方式进行面向对象的编程.python优雅的语法和动态的类型,再结合它的解释性,使 ...
- 20155216 2016-2017-2《Java程序设计》课程总结
20155216 2016-2017-2<Java程序设计>课程总结 (按顺序)每周作业链接汇总 预备作业1:简要内容:我对师生关系的见解 预备作业2:简要内容:有关C语言学习调查以及学习 ...
- 20155322 2017-2018-1 《信息安全系统设计》第五周 MyBash实现
#20155322 2017-2018-1<信息安全系统设计>第五周 MyBash实现 [博客目录] 实现要求 相关知识 bash fork exec wait 相关问题 fork返回两次 ...
- HTMl+CSS 模仿京东网登录页面
课后实践项目,仅页面效果,写博客纯属记录! 码云开源仓库地址:https://gitee.com/ynavc/jd 演示地址:https://ynavc.gitee.io/jd 效果图: 实现代码: ...
- 《Java 程序设计》课堂实践项目 课后学习总结
<Java 程序设计>课堂实践项目 课后学习总结 String类的使用(sort) 目录 Linux命令(sort) 课堂实践 课后思考 学习老师的代码之后的思考:int与Integer ...
- 《python编程:从入门到实践》课后习题及答案
转载: <Python编程:从入门到实践>课后习题及答案-码农之家 (xz577.com) <Python编程:从入门到实践>课后习题及答案 - 信德维拉 - 博客园 (cnb ...
随机推荐
- 为什么要用 C# 来作为您的首选编程语言
因为您可以用,并且也是您的最佳选择!之所以可用,是因为 C# 能够很好地在 Mac.Linux.Android 和 iOS 上运行(对了,还有 Windows):它可以在您最喜爱的编辑器上运行:它在一 ...
- 使用EXCEL 完成分组统计
表testTable 有以下数据,要统计各个电视剧的数量.在开发人员看来,使用sql操作完成select name,count(*) from TestTable where 1=1 group by ...
- AngularJS之过滤器
AnularJS的过滤器用来格式化需要展示给用户的数据,有很多实用的内置过滤器,也可以自己编写. 在HTML中的模板绑定符号{{ }}内通过|符号来调用过滤器.例如,假设我们希望将字符串转换成大写,可 ...
- Visualizing LSTM Layer with t-sne in Neural Networks
LSTM 可视化 Visualizing Layer Representations in Neural Networks Visualizing and interpreting represent ...
- Android app启动是出现白屏或者黑屏如何解决?
1.为什么 APP 启动时会出现白屏或者黑屏? 当打开一个 Activity 时,如果这个 Activity 所属的应用还没有在运行,系统会为这个 Activity 所属的应用创建一个进程,但进程的创 ...
- Material适配1 - 入门篇
版权声明: 欢迎转载,但请保留文章原始出处 作者:GavinCT 出处:http://www.cnblogs.com/ct2011/p/4493384.html 随着Material Design的普 ...
- 【java8】为java8的foreach正名
首先为自己没有经过严格测试得出的错误结论感到抱歉,原博文,测试完感觉自己发现了一个新bug,后来思前想后觉得不应该是这样的,如果效率差的这么多,jdk的开发人员会不去优化它吗,但是怎么重复测试任然得到 ...
- GIT速成
安装工具与使用工具: GIT工具 :https://www.git-scm.com/download/ WINGDOWS图形界面工具:https://download.tortoisegit.org/ ...
- centos 安装golang笔记
1.使用yum安装 yum install go 这个命令可以将go环境安装到linux上. 2.配置gopath 第一步安装成功的go命令会被放入/usr/lib/golang/bin /usr/l ...
- 干货:如何使用N点虚拟管理系统?
N点虚拟主机管理系统怎么用呢?最近有许多朋友问我关于这款虚拟主机管理系统如何使用?在讲如何使用N点虚拟主机管理系统之前,我们先来了解一下N点虚拟主机管理系统的介绍. N点虚拟主机管理系统 ...