20165329 mybash的实现
20165329 mybash的实现
实验要求
- 使用fork,exec,wait实现mybash
- 写出伪代码,产品代码和测试代码
- 发表知识理解,实现过程和问题解决的博客(包含代码托管链接)
使用fork,exec,wait实现mybash
fork
首先用man命令查看fork的使用方法

- 其功能
通过复制调用fork的进程创建一个新进程。
- 返回值
创建子进程成功时,fork在父进程中返回子进程的pid,在子进程中返回0。失败时,在父进程中返回-1,无子进程被创建,相应的错误在errno中设置。
- 
[fork创建子进程代码] #include <unistd.h> 
 #include <stdio.h>
 #include <stdlib.h>
 int main(void)
 {
 char *msg;
 int n;
 pid_t pid;
 pid = fork();
 if (pid < 0) {
 perror("fork failed");
 exit(1);
 }
 if (pid == 0) {
 msg = "This is in child progress\n";
 n = 6;
 } else {
 msg = "This is in parent progress\n";
 n = 3;
 }
 for (; n > 0; --n) {
 printf("%s", msg);
 //sleep(1);
 }
 return 0;
 }
- fork创建子进程代码

将代码中加入sleep(1)重新编译并运行程序得到运行结果:

其不同的原因为当程序执行fork()语句后就又多出了一个进程,进程的运行符合“多个进程的运行方式”。
exec()
首先用man命令查看exec的使用方法

- 其功能
当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。
- 返回值
这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回,如果调用出错则返回-1,所以exec函数只有出错的返回值而没有成功的返回值。
- 
exec_call.c 
int main(void)
{
printf("hello, world\n");
return 0;
}
- 
exec_test.c #include <unistd.h> 
 #include <stdio.h>
 int main(void)
 {
 char *const argv[] ={"exec_call", NULL};
 execv("./exec_call", argv);
 printf(“here here\n”);
 return 0;
 }
- 验证exec功能代码

当进程调用execv函数时,该进程的用户空间代码和数据完全被exec_call替换,从exec_call的启动例程开始执行。调用execv进程后面的代码没有被执行。所以出现了错误。
- 解决方法
在“fork创建子进程代码”中加入execv函数,改进的函数pro_control3.c:
#include <unistd.h> 
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
	char	*msg;
	int	n;
	pid_t	pid;
	pid	= fork();
	if (pid < 0) {
		perror("fork failed");
		exit(1);
	}
	if (pid == 0) {
	msg	= "This is in child progress\n";
	n	= 6;
	char *const argv[] ={"exec_call", NULL};
	execv("./exec_call", argv);
        }
        else {
		msg	= "This is in parent progress\n";
		n	= 3;
	}
	for (; n > 0; --n) {
		printf("%s", msg);
		//sleep(1);
	}
	return 0;
}

wait
首先用man命令查看wait的使用方法
- 功能
对于一个已经终止的子进程,用wait能够让系统释放与子进程相关的资源;如果不用wait则终止的进程会变为僵尸进程。
- 返回值
若调用成功则返回清理掉的子进程id,若调用出错则返回-1。
mybash代码
- 伪代码
- 对用户输入的命令进行解析
- 检查用户输入的命令是否为内置的Linux命令
- 构造argv向量
- 
mybash.c代码: 
#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;
}
- 结果![]() 
实验中的问题
实现mybash功能一开始没有加/bin,ls不能用,后面发现在前面加上“/bin”就可以了。
感想
本题根据网上搜索查询然后慢慢的一步一步做,深有体会,自己学的很多不足,以后的努力学好每一个知识点。
 
                    
                

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号