基于fork(),execvp()和wait()实现类linux下的bash——mybash

基于fork(),execvp()和wait()实现类linux下的bash——mybash

预备知识

  • fork():fork()函数经过系统调用建立一个与原来进程几乎彻底相同的进程,也就是两个进程能够作彻底相同的事,但若是初始参数或者传入的变量不一样,两个进程也能够作不一样的事http://blog.csdn.net/jason314/article/details/5640969
    • 重点是后一句话,若是初始参数或者传入变量不一样,两个进程也能够作不一样的事,意思就是虽然父进利用fork()函数创造了一个和本身彻底一致的子进程,但因为子进程执行指针开始至位于fork()函数后,意思就是子进程不会再执行一次fork()上面的代码,全部的fork()前定义的变量,都将保持初始化的值。
  • wait():进程一旦调用了wait,就当即阻塞本身,由wait自动分析是否当前进程的某个子进程已经退出,若是让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它完全销毁后返回;若是没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止,wait其实比较好理解http://blog.sina.com.cn/s/blog_759803690101aqeq.html
  • execvp():exec系统调用会从当前进程中把当前程序的机器指令清除,而后在空的进程中载入调用时指定的程序代码,最后运行这个新的程序http://www.linuxidc.com/Linux/2011-10/44527.htm.
    • 这样的定义就意味着,全部execvp()后面的代码都将不被执行,至关于在主函数里“重写”了一遍传入execvp函数中的程序,又在紧接着在后面加了句exit(1);这样每每带来不便,但根据定义,咱们能够将fork和execvp结合,从而保护父进程。

产品伪代码

Step1:读入用户输入的指令;
Step2:调用fork函数生成一个子进程,并将fork返回的pid值赋给fpid;
Step3:调用wait函数,传入null;
Step4:判断fpid是否为零,若是为零执行Step5;若是不为零,执行Step6;
Step5:调用execvp函数,并把用户输入的指令传进去;
Step6:返回Step1;

产品代码

#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h>
#include    <unistd.h>
#include    <sys/types.h>
#include    <sys/wait.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] = '\0';      
    cp = malloc( strlen(buf)+1 );       
    if ( cp == NULL ){          
        fprintf(stderr,"no memory\n");
        exit(1);
    }
    strcpy(cp, buf);        
    return cp;          
}
int mybash(char *arglist[])
{
    
    int flag=0;
    flag=fork();
    wait(NULL);
    if(flag==0) 
    execute( arglist );
else return 1;
}

测试代码

#include<stdio.h>
#include    <string.h>
#include"head.h"
int mybash(char *arglist[]);
int test1()
{
char *test1[10],*test2[10],*test3[10],*test4[10],*test5[10],*test6[10];
test1[0]="ls";
test1[1]="-l";
test1[2]=0;

test2[0]="od";
test2[1]="-tc";
test2[2]="-tx1";
test2[3]="12.txt";
test2[4]=0;

test3[0]="mkdir";
test3[1]="success";
test3[2]=0;

test4[0]="git";
test4[1]="add";
test4[2]=".";
test4[3]=0;

test5[0]="git";
test5[1]="commit";
test5[2]="-m";
test5[3]="\"test11\"";
test5[4]=0;

test6[0]="git";
test6[1]="push";
test6[2]="origin";
test6[3]="master";
test6[4]=0;

int flag=0;
if(flag=mybash(test1)==1)printf("\n%s %s test Success!\n",test1[0],test1[1]);

flag=0;
if(flag=mybash(test2)==1)printf("\n%s %s %s %s test Success!\n",test2[0],test2[1],test2[2],test2[3]);

flag=0;
if(flag=mybash(test3)==1)printf("\n%s %s test Success!\n",test3[0],test3[1]);

flag=0;
if(flag=mybash(test4)==1)printf("\n%s %s %s test Success!\n",test4[0],test4[1],test4[2]);

flag=0;
if(flag=mybash(test5)==1)printf("\n%s %s %s %s test Success!\n",test5[0],test5[1],test5[2],test5[3]);

flag=0;
if(flag=mybash(test6)==1)printf("\n%s %s %s %s test Success!\n",test6[0],test6[1],test6[2],test6[3]);

return 0;
}
  • 测试运行截图

问题及解决方法

  • 问题1:由于使用的是execvp函数是放在主函数里的,每每都会直接终结掉父进程,这是主要问题;
  • 问题1解决:调用fork函数生成一个子进程,而且只容许execvp运行在子进程中,这样execvp终结掉的就只是子进程,而不会影响父进程,而对于fork函数完整复制父进程的子进程也会由于调用了execvp而及时终结掉,不会致使一个无谓的循环。
  • 问题2:怎么实现只让execvp运行在子进程,而不去影响父进程
  • 问题2解决:这是根本问题,解决了才能使得mybash正常的去运行去循环,由于fork函数的特性就是完整复制父进程,但子进程永远都是从fork后面执行意思就是,fork前面的变量将保持初始化的值,而不受fork前面的代码影响,因此,这里可使用fpid来做为flag判断这是一个子进程仍是一个父进程,若是是一个子进程那么就运行execvp,若是不是就返回继续执行父进程;

运行截图

码云连接

相关文章
相关标签/搜索