• 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;  
        } 
    
    • 执行结果

    • 注意点:第二个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.
    ",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= '';
    		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命令发现没办法正常执行,但是执行一个可执行文件就没有问题

      根据提示得知,是因为没有找到此命令,猜测应该是路径有问题,第一个命令行参数argv[0]应该给出完整的路径名,因此将命令改为/bin/ls、/bin/ps就没问题了

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

    • 运行结果如下

  • 相关阅读:
    yum和apt-get用法及区别
    Vim终极指南:所思即所得
    Vim 操作符命令和动作命令
    vim中文手册
    标准代码页(codepage)列表
    中文字符集编码Unicode ,gb2312 , cp936 ,GBK,GB18030
    vim在系统剪切板的复制与粘贴
    linux中高亮显示文本的工具 -- bat
    pandas category数据类型
    pandas 数据类型转换
  • 原文地址:https://www.cnblogs.com/rafell/p/7690764.html
Copyright © 2020-2023  润新知