微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

20165329 mybash的实现

20165329 mybash的实现

实验要求

使用fork,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

 

          #include <stdio.h>

 

 

          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代码

  1. 用户输入的命令进行解析
  2. 检查用户输入的命令是否为内置的Linux命令
  3. 构造argv向量

#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”就可以了。

感想

本题根据网上搜索查询然后慢慢的一步一步做,深有体会,自己学的很多不足,以后的努力学好每一个知识点。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐