课后实践之mybash

实践要求

加分题-mybash的实现

  • 使用fork,exec,wait实现mybash
  • 写出伪代码,产品代码和测试代码
  • 发表知识理解,实现过程和问题解决的博客(包含代码托管链接)

预备知识

  1. 关于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键即可自动补全已部分输入的程序名、文件名、变量名等等。
  2. 操作系统的核心

    • 文件:字节序列
    • 虚拟内存:字节数组抽象出外设和主存
    • 进程:操作系统对一个正在运行的程序的一种抽象
  3. 操作系统的功能

    • “管家婆”:管理各种硬件资源

    • “服务生” :提供接口

      -->为用户提供shell(写代码)

      -->为程序猿提供系统调用

  4. 关于进程

    • 进程的状态:

      • 创建(created)
      • 执行(running)
      • 就绪(ready)
      • 阻塞(blocked)
      • 终止(terminated)

实践过程

准备工作

  1. 查询相关命令

    • man -k process命令查看与进程(process)相关的命令,发现有很多很多:

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



      其描述为:

      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命令用来执行文件

  2. 模块分析:

    • 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():获得自己的pid
        • getppid():获得父进程的pid
        • sleep():延迟指定数量的时间(作为函数参数,单位为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);
        }
        • 运行结果:
  3. 伪代码

    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命令中文显示问题

解决方法

参考资料

课后实践之mybash20155314的更多相关文章

  1. 第3周课后实践&#183;程序阅读(4)-利用引用訪问私有数据成员

    /* * Copyright (c) 2015, 烟台大学计算机学院 * All rights reserved. * 文件名:test.cpp * 作 者:刘畅 * 完毕日期:2015年 3 月 2 ...

  2. 小垃圾myl的课后实践

    #include<iostream> #include<cstdio> using namespace std; int main(){ ,flag=; printf(&quo ...

  3. 00java语法基础和课后实践

    一:运行代码,并分析结果 代码1: package reserve; public class Main { public static void main(String[] args) { Size ...

  4. 零基础python入门(1)

    1.前景及准备 (1).python是一门简单易学且功能强大的编程语言.它拥有高效的高级数据结构,并且能用简单而又高效的方式进行面向对象的编程.python优雅的语法和动态的类型,再结合它的解释性,使 ...

  5. 20155216 2016-2017-2《Java程序设计》课程总结

    20155216 2016-2017-2<Java程序设计>课程总结 (按顺序)每周作业链接汇总 预备作业1:简要内容:我对师生关系的见解 预备作业2:简要内容:有关C语言学习调查以及学习 ...

  6. 20155322 2017-2018-1 《信息安全系统设计》第五周 MyBash实现

    #20155322 2017-2018-1<信息安全系统设计>第五周 MyBash实现 [博客目录] 实现要求 相关知识 bash fork exec wait 相关问题 fork返回两次 ...

  7. HTMl+CSS 模仿京东网登录页面

    课后实践项目,仅页面效果,写博客纯属记录! 码云开源仓库地址:https://gitee.com/ynavc/jd 演示地址:https://ynavc.gitee.io/jd 效果图: 实现代码: ...

  8. 《Java 程序设计》课堂实践项目 课后学习总结

    <Java 程序设计>课堂实践项目 课后学习总结 String类的使用(sort) 目录 Linux命令(sort) 课堂实践 课后思考 学习老师的代码之后的思考:int与Integer ...

  9. 《python编程:从入门到实践》课后习题及答案

    转载: <Python编程:从入门到实践>课后习题及答案-码农之家 (xz577.com) <Python编程:从入门到实践>课后习题及答案 - 信德维拉 - 博客园 (cnb ...

随机推荐

  1. 为什么要用 C# 来作为您的首选编程语言

    因为您可以用,并且也是您的最佳选择!之所以可用,是因为 C# 能够很好地在 Mac.Linux.Android 和 iOS 上运行(对了,还有 Windows):它可以在您最喜爱的编辑器上运行:它在一 ...

  2. 使用EXCEL 完成分组统计

    表testTable 有以下数据,要统计各个电视剧的数量.在开发人员看来,使用sql操作完成select name,count(*) from TestTable where 1=1 group by ...

  3. AngularJS之过滤器

    AnularJS的过滤器用来格式化需要展示给用户的数据,有很多实用的内置过滤器,也可以自己编写. 在HTML中的模板绑定符号{{ }}内通过|符号来调用过滤器.例如,假设我们希望将字符串转换成大写,可 ...

  4. Visualizing LSTM Layer with t-sne in Neural Networks

    LSTM 可视化 Visualizing Layer Representations in Neural Networks Visualizing and interpreting represent ...

  5. Android app启动是出现白屏或者黑屏如何解决?

    1.为什么 APP 启动时会出现白屏或者黑屏? 当打开一个 Activity 时,如果这个 Activity 所属的应用还没有在运行,系统会为这个 Activity 所属的应用创建一个进程,但进程的创 ...

  6. Material适配1 - 入门篇

    版权声明: 欢迎转载,但请保留文章原始出处 作者:GavinCT 出处:http://www.cnblogs.com/ct2011/p/4493384.html 随着Material Design的普 ...

  7. 【java8】为java8的foreach正名

    首先为自己没有经过严格测试得出的错误结论感到抱歉,原博文,测试完感觉自己发现了一个新bug,后来思前想后觉得不应该是这样的,如果效率差的这么多,jdk的开发人员会不去优化它吗,但是怎么重复测试任然得到 ...

  8. GIT速成

    安装工具与使用工具: GIT工具 :https://www.git-scm.com/download/ WINGDOWS图形界面工具:https://download.tortoisegit.org/ ...

  9. centos 安装golang笔记

    1.使用yum安装 yum install go 这个命令可以将go环境安装到linux上. 2.配置gopath 第一步安装成功的go命令会被放入/usr/lib/golang/bin /usr/l ...

  10. 干货:如何使用N点虚拟管理系统?

    N点虚拟主机管理系统怎么用呢?最近有许多朋友问我关于这款虚拟主机管理系统如何使用?在讲如何使用N点虚拟主机管理系统之前,我们先来了解一下N点虚拟主机管理系统的介绍. ​      N点虚拟主机管理系统 ...