20155321 第七周课堂实践

实践任务

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

预备知识

  • fork()
    • 目的:创建一个与原来进程几乎完全相同的进程,但是假如两个进程也可以完成不同的请求
    • 练习代码如下:
     #include <unistd.h>  
     #include <stdio.h>   
     int main ()   
      {   
          pid_t pid; //fpid表示fork函数返回的值  
          int count=0;  
          pid=fork();   
    
          if (pid < 0)   
              printf("error in fork!");   
          else if (pid == 0) {  
              printf("i am the child process, my process id is %d/n",getpid());   
              count++;  
          }  
          else {  
              printf("i am the parent process, my process id is %d/n",getpid());   
              count++;  
          }  
          printf("统计结果是: %d/n",count);  
          return 0;  
      } 
    • 执行结果
      1071532-20171206201124081-2004068032.png
    • 注意点:第二个count值不会是2,因为count是一个独立变量,而不是父进程和子进程共用的
    • 参考资料
  • exec()
    • 目的:提供一个在进程中启动另一程序执行的方法。它可根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段。执行完后,原调用进程的内容除了进程号外,其他均被新程序的内容替换
    • 函数原型:int execve(const char *filename, char *const argv[], char *const envp[]);其中执行程序由filename决定,filename必须是一个二进制的可执行文件
  • wait()
    • 目的:用在父进程中等待回收子进程的资源,而防止僵尸进程的产生
  • 函数原型:int waitpid(pid_t pid, int* statloc, int options);
  • 参考资料

任务分析

  • bash是一个交互型的应用程序,主要解析并代表用户执行一系列的命令。

  • 在我的mybash中主要实现两个功能,分别是若用户输入的是Linux命令,则直接执行此命令;若用户输入的是一个可执行文件则运行此文件。

  • 因此可得出初步的思路

主函数{
    while(1)  //不断循环执行命令
    {
        得到用户输入的命令;
        调用子函数1解析此命令
    }
}

子函数1{
    调用子函数2对用户输入的字符串进行解析,根据空格区分各个参数,为之后调用execve函数做准备;
    
    调用execve函数执行子进程;
    
}
  • 具体实现代码如下,参考了课本P513-P526的内容
#include <stdio.h>
#include <unistd.h>
#include <wait.h>
#include <stdlib.h>
#include <string.h>
#define MAX 128

void eval (char *cmdline);  //对用户输入的命令进行解析
int parseline (char *buf, char **argv);
int builtin_command(char **argv);

int main()
{
    char cmdline[MAX];
    
    while(1){
        printf("> ");
        fgets(cmdline,MAX,stdin);
        if(feof(stdin))
        {
            printf("error");
            exit(0);
        }
        eval(cmdline);
    }
}

void eval(char *cmdline)
{
    char *argv[MAX];
    char buf[MAX];
    int bg;
    pid_t pid;
    char *envp[]={0,NULL};
    strcpy(buf,cmdline);
    bg = parseline(buf,argv);//解析以空格分隔的命令行参数,填入argv数组中
    if(argv[0]==NULL)
        return;
    if(!builtin_command(argv)) //调用此函数检查用户输入的命令是否为内置的Linux命令,是则执行并返回1,不是则返回0
    {   
    if((pid=fork()) == 0)
    {
        if(execve(argv[0],argv,envp) < 0) {
            printf("%s : Command not found.\n",argv[0]);
            exit(0);
        }
    }

    if(!bg){
        int status;
        if(waitpid(-1,&status,0) < 0)  //相当于调用wait函数
            printf("waitfg: waitpid error!");
    }
    else
        printf("%d %s",pid, cmdline);
    return;
    }
}

int builtin_command(char  **argv)
{
    if(!strcmp(argv[0], "quit"))
        exit(0);
    if(!strcmp(argv[0],"&"))
        return 1;
    return 0;
}

int parseline(char *buf,char **argv)//解析以空格分隔的命令行参数,并构造最终传给execve函数的argv向量
{
    char *delim;
    int argc;
    int bg;

    buf[strlen(buf)-1]=' ';
    while(*buf && (*buf == ' '))
        buf++;

    argc=0;
    while( (delim = strchr(buf,' '))){   //从字符串buf中寻找空格字符第一次出现的位置
        argv[argc++] = buf;
        *delim= '\0';
        buf = delim + 1;
        while(*buf && (*buf == ' '))
            buf++;
    }

    argv[argc] = NULL;
    if(argc == 0)
        return 1;
    if((bg=(*argv[argc-1] == '&')) != 0)
        argv[--argc] = NULL;
    return bg;
}

问题及解决

  • 一开始在执行命令的时候,直接输入ls、ps命令发现没办法正常执行,但是执行一个可执行文件就没有问题
    1071532-20171019090723740-614656518.png
    根据提示得知,是因为没有找到此命令,猜测应该是路径有问题,第一个命令行参数argv[0]应该给出完整的路径名,因此将命令改为/bin/ls、/bin/ps就没问题了

  • 目前的程序在执行Linux命令时还是需要把完整路径名给打出来,还不能像终端那样直接打命令,在这一点上要是能改进就好了

  • 运行结果如下
    1071532-20171019090028349-1001354778.png

转载于:https://www.cnblogs.com/rafell/p/7690764.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值