天天看點

Linux系統程式設計--實作簡單shell

上個部落格我們講了程序如何替換,以及exec函數族是,接下來我們來應用這些函數以及之前學的知識來實作一個簡單shell。

如果不太清楚,請先看看之前的内容;

1.程序建立

2.程序等待

3.程序替換

我們先看系統的shell是如何實作?

Linux系統程式設計--實作簡單shell

我們敲一行指令,然後按回車,這個指令就被執行,玩了之後他他又傳回到原來的狀态,這個指令還可以加上選項,例這些選項之間用空格間隔開。并且空格可以是多個。如下圖,

從左到右表示時事件發生的次序,shell從使用者讀入字元串“ls",然後建立一個心得程序,接着在這個心得程序裡面運作新的程式,并等待新的程序運作結束。接着shell讀取新的一行指令,建立一個新的程序,生在這個程序中運作程式,并等待這個程序結束。

Linux系統程式設計--實作簡單shell

是以我們要實作一個shell,就需要循環下面幾步:

1. 擷取指令行

2. 解析指令行

3. 建立一個子程序(fork)

4. 替換子程序(exec)

5. 父程序等待子程序退出(wait)

代碼如下:

/*模拟實作簡易shell
 * 功能:myshell> ls
 *      能夠執行各種指令
*/
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<string.h>


char *argv[32];
int argc = 0;
int param_parse(char *buff)     //解析字元串的函數
{
    //ls -l -a
    if(buff==NULL)  //字元串為空,跳出
        return -1;
    char *ptr = buff;//ptr用來存放目前字元串
    char *tmp = ptr;
    argc = 0;
    while((*ptr)!='\0')
    {
        //當遇到空格,并且下個字元不是空格
        //将空格空格位置置'\0',此時就相當于截斷了一個字元串,然後将這個字元串儲存再字元指針數組裡面
        //然後将使用argv[argc]來儲存字元串的位置
        if(*ptr == ' '&&*(ptr+1)!=' ')
        {
            *ptr='\0';
            argv[argc]=tmp;//儲存空格之前的字元串
            
            tmp=ptr+1;//将指針指向空格的下個字元
            argc++;//數組下标+1
        }
        ptr++;//ptr往後周遊
    }
    argv[argc++] = tmp;//循環跳出,說明已經是最後一個字元串,儲存後再将下個指針置NULL
    argv[argc] = NULL;
    return 0;
}

int exec_cmd()  //建立子程序,并且替換
{
    int pid = 0;
    pid = fork();//建立子程序
    if(pid < 0)
    {
        return -1;
    }
    else if(pid == 0)//如果是子程序,則替換程式
    {
        execvp(argv[0],argv);//進行替換
        exit(0);//執行完要退出程序,不能return 
    }
    //到這裡就說明是父程序
    int statu;//用來儲存程序推出的資訊
    wait(&statu);//擷取信退出資訊
    if(WIFEXITED(statu))//判斷子程序是否正常退出,非0則表示正常退出
    {
        printf("%s\n",strerror(WEXITSTATUS(statu)));//擷取後取其裡面的退出碼,再用strerroe列印出退出資訊
    }
    return 0;
}

int main()
{
    char buff[1024] = {0};
    while(1)
    {    
        printf("myshell> ");
        scanf("%[^\n]%*c",buff);
        //%[^\n]擷取資料直到遇到\n為止
        //%*c  清空緩沖區,資料都不要了,這樣做是為了不對下次的緩沖區中輸入的指令造成影響
        printf("%s\n",buff);
        param_parse(buff);
        exec_cmd();
    }
    return 0;
}

           

效果如下:

Linux系統程式設計--實作簡單shell

是不是還挺炫酷的捏!?

繼續閱讀