上個部落格我們講了程序如何替換,以及exec函數族是,接下來我們來應用這些函數以及之前學的知識來實作一個簡單shell。
如果不太清楚,請先看看之前的内容;
1.程序建立
2.程序等待
3.程序替換
我們先看系統的shell是如何實作?
我們敲一行指令,然後按回車,這個指令就被執行,玩了之後他他又傳回到原來的狀态,這個指令還可以加上選項,例這些選項之間用空格間隔開。并且空格可以是多個。如下圖,
從左到右表示時事件發生的次序,shell從使用者讀入字元串“ls",然後建立一個心得程序,接着在這個心得程序裡面運作新的程式,并等待新的程序運作結束。接着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;
}
效果如下:
是不是還挺炫酷的捏!?