zoukankan      html  css  js  c++  java
  • 课后实践之mybash20155314

    课后实践之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. 关于进程

      NsTdx.png

      • 进程的状态:
        • 创建(created)
        • 执行(running)
        • 就绪(ready)
        • 阻塞(blocked)
        • 终止(terminated)

    实践过程

    准备工作

    1. 查询相关命令

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

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

        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命令:
        Nwmef.png

      • man -k execute | grep 2命令找到execve命令:
        NwMFg.png
        其描述为:

        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
        ");
              execvp("ls", arglist);
              printf("* * * ls is done. bye");
          
              return 0;
          }
        
        • 功能:
          调用execvp()函数,用man命令查看该函数的用法为:NsbFK.pngexec函数会将当前的进程替换为一个新的进程,这个新的进程可以由路径或者文件参数指定。
        • 运行结果:
          NrI58.png
      • 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] = '';
              cp = malloc(strlen(buf) + 1);
              if (cp == NULL) {
                  fprintf(stderr, "no memory
        ");
                  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 != '
        ')
                      arglist[numargs++] = makestring(argbuf);
                  else {
                      if (numargs > 0) {
                          arglist[numargs] = NULL;
                          execute(arglist);
                          numargs = 0;
                      }
                  }
              }
              return 0;
          }
        
        • 功能:一次性bash。
        • 运行结果:
          NyuT0.png
      • 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
        ", mypid);
              ret_from_fork = fork();
              sleep(1);
              printf("After: my pid is %d, fork() said %d
        ", getpid(), ret_from_fork);
          
              return 0;
          }
        
        • 功能:即fork的功能,除pid之外复制(duplicate)出一个一模一样的子进程,如同克隆。
        • 运行结果:NyG6J.png
      • forkdemo2.c:

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

          #include <stdio.h>
          #include <stdlib.h>
          #include <unistd.h>
          
          int main() {
              int fork_rv;
          
              printf("Before: my pid is %d
        ", 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
        ", getpid());
          
                  exit(0);
              } else {
                  printf("I am the parent. my child is %d
        ", fork_rv);
                  exit(0);
              }
          
              return 0;
          }
        
        • 功能:通过fork()的返回值来区分是父进程还是子进程:如果返回一个大于0的数(子进程的Pid)则为父进程;如果返回值为0则为子进程;如果返回值为负值则出错。
        • 运行结果:Ny3pF.png
      • 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
        ", li++);
                      sleep(1);
                      printf("child gi:%d
        ", gi++);
                      printf("child si:%d
        ", si++);
                  }
                  exit(0);
          
              } else {
                  for (i = 0; i < 5; i++) {
                      printf("parent li:%d
        ", li++);
                      printf("parent gi:%d
        ", gi++);
                      sleep(1);
                      printf("parent si:%d
        ", si++);
                  }
                  exit(0);
          
              }
              return 0;
          }
        
        • 相关函数:

          • getpid():获得自己的pid
          • getppid():获得父进程的pid
          • sleep():延迟指定数量的时间(作为函数参数,单位为s)
        • 运行结果:Nydk6.png

      • 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
        ", getpid(), delay);
              sleep(delay);
              printf("child done. about to exit
        ");
              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
        ",
                     childpid, wait_rv);
          }
          
          int main() {
              int newpid;
              printf("before: mypid is %d
        ", getpid());
              if ((newpid = fork()) == -1)
                  perror("fork");
              else if (newpid == 0)
                  child_code(DELAY);
              else
                  parent_code(newpid);
          
              return 0;
          }
        
        • 运行结果:NyDpD.png

        • 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
          ", getpid(), delay);
                sleep(delay);
                printf("child done. about to exit
          ");
                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
          ", 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
          ", high_8, low_7, bit_7);
            }
            
            int main() {
                int newpid;
            
                printf("before: mypid is %d
          ", getpid());
            
                if ((newpid = fork()) == -1)
                    perror("fork");
                else if (newpid == 0)
                    child_code(DELAY);
                else
                    parent_code(newpid);
            }
          
          • 运行结果:Ny0fO.png
    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] = '';      
        cp = malloc( strlen(buf)+1 );       
        if ( cp == NULL ){          
            fprintf(stderr,"no memory
    ");
            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 != '
    ')
                arglist[numargs++] = makestring(argbuf);
            else {
                if (numargs > 0) {
                    arglist[numargs] = NULL;
                    mybash20155314(arglist);
                    numargs = 0;
                }
            }
        }
        return 0;
    }
    

    运行结果

    Nypwt.png

    代码调试过程中遇到的问题

    macOS High Sierra下终端man命令中文显示问题

    NsxOA.png

    解决方法

    NySeI.png

    参考资料

  • 相关阅读:
    vue六十五:vuex-getters和vuex-mapGetters
    vue六十四:vuex-mapStore
    vue六十三:vuex的异步处理
    vue六十二:vuex的同步状态管理和调试工具vue-devtools
    vue六十一:使用vuex管理状态示例
    vue六十:电影院售票项目案例之影院页面和使用Better-Scroll实现拖拉滚动
    vue五十九:电影院售票项目案例之详情页面
    vue五十八:电影院售票项目案例之项目吸顶效果
    ingress 413 Request Entity Too Large
    kubeadm搭建K8S集群
  • 原文地址:https://www.cnblogs.com/crazymosquito/p/7712151.html
Copyright © 2011-2022 走看看