考虑下面这个与shell典型的互动:
用下面的时间轴来表示时间发生的次序,其中时间从左到右。shell由标识的方块代表,它随着时间的流逝从左向右移动。shell从用户读入字符串“ls”。shell建立一个新的进程,然后在那个进程中运行ls程序并等待那个进程结束。
然后shell读取新的一行输入,建立一个新的进程,在这个进程中运行程序,并等待这个进程结束。所以要写一个shell,需要循环以下过程:
- 获取命令行
- 解析命令行
- 建立一个子进程(fork)
- 替换子进程(execvp)
- 父进程等待子进程退出(wait)
根据这些思路,和我们前面的学的关于进程的技术,就可以自己实现一个shell了。
实现思路
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
#include<ctype.h>
#include<sys/types.h>
#include<sys/wait.h>
#define MAX_CMD 1024
char command[MAX_CMD];
int do_face()
{
memset(command, 0x00, MAX_CMD);
printf("minishell$ ");
fflush(stdout);
if(scanf("%[^\n]%*c", command) == 0)
{
getchar();
return -1;
}
return 0;
}
char **do_parse(char *buff)
{
int argc = 0;
static char *argv[32];
char *ptr = buff;
while(*ptr != '\0')
{
if(!isspace(*ptr))//判断一个字符是否为空格字符
{
argv[argc++] = ptr;
while(!isspace(*ptr) && (*ptr) != '\0')
{
{
ptr++;
}
}
else{
while(isspace(*ptr)){
*ptr = '\0';
ptr++;
}
}
}
argv[argc] = NULL;
return argv;
}
int do_exec(char *buff)
{
char **argv = {NULL};
int pid = fork();
if(pid == 0)
{
argv = do_parse(buff);
if(argv[0] == NULL)
{
exit(-1);
}
execvp(argv[0], argv);
}
else{
waitpid(pid, NULL, 0);
}
return 0;
}
int main()
{
while(1)
{
if(do_face() < 0)
{
continue;
}
do_exec(command);
}
return 0;
}