上个博客我们讲了进程如何替换,以及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;
}
效果如下:
是不是还挺炫酷的捏!?