基於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,若是不是就返回繼續執行父進程;

運行截圖

碼雲連接

相關文章
相關標籤/搜索