学过exec系列函数后,我尝试自行实现一个shell程序,
先上代码
#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<stdlib.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<unistd.h>
#define Num 32;
using namespace std;
int main()
{
char buff[1024]={0};
for(;;){
string tips = " [XXX@host_local YYY]# ";
cout << tips;
fgets(buff,sizeof(buff)-1,stdin);
buff[strlen(buff)-1] = 0;
char *argv[Num];
argv[0] = strtok(buff," ");
int i=0;
while(argv[i]!=NULL){
i++;
argv[i] = strtok(buff," ");
}
pid_t id=0;
if(id==0){
cout << " child is running ..." << endl;
execv(argv[0],argv);
exit(123);
}
else{
int status=0;
waitpid(id,&status,0);
cout << " code erro:" << WEXETSTATUS(status)<< endl;
}
}
return 0;
}
大致思路:
要想写出一个和系统类似的shell,我们需要:
- 写入命令行
- 解析命令行
- 建立子进程
- 替换子进程
- 父进程等待子进程退出
写入命令行
首先我们需要写一个格式如操作系统内核的shell , [XXX@host_local YYY]# ,来提示我们接下来要输出命令,打印出来,下来就是要写入操作了,那么这个操作是由用户自行写入,也就是要从键盘上写入,我们使用了函数fgets(),这时候注意,用户在键盘输入是,最后是以回车提交,而如果fgets()会把回车一并读取上来,所以我们手动把buff数组的最后一个元素设置为0才行。
解析命令行
要解析我们刚刚写入的命令,就要用到strtok函数,以空格为分隔符将刚刚写入的buff数组解析到新数组argv[ ]中,循环写入,需要注意的是,strtok函数会把分割前的字符串破坏掉,即每次分割后,原来的字符串就会少掉一部分,完整性会被破坏。
建立子进程
这个程序的主要目的,就是创建一个子进程,让这个子进程替换成我们写入的命令行,也是体现整个代码核心思想的代码段,用到了execv()函数,此时传入的第一个参数,就是刚刚收到命令行解析的argv[ ]数组的首元素,第二个参数就是argv这个数组。
父进程等待子进程退出
最后父进程等待子进程退出,