要求:
第0步:写一个最简单的shell命令解释器,本程序取自APUE例1-5,命令不能带参数。
学员需要完成的内容如下:
命令解释器首先是一个死循环。
打印一个命令提示符。
取得命令行输入放在数组里面,不要求命令带参数。可以getc()、fgets()、scanf()等。
如果用fgets()的话,取得的字符串包括最后输入的换行符,故要去掉命令字符串末尾的“\n”,变成“\0”。
创建一个子进程,调用exec执行命令。
父进程调用waitpid()等待子进程的退出,然后进入下一次循环。
第1步:写一个shell命令解释器,使能处理带参数的命令。
学员需要完成的内容如下:
命令解释器首先是一个死循环。
打印一个命令提示符,包含当前路径信息。取得命令行输入,本程序是把命令行输入保存在一个字符指针指向的地址中。
分析命令行,把以空格分开的命令和参数
分别取出来放在字符指针数组arg[]中。这里取得的命令行字符串保存在input指向的地址。为了把这一行字符串中的命令和参数分开,需要一个临时数组tmp(本程序是重用前面使用的buf数组),把input指向命令行中的命令和参数分别保存在arg[0]、arg[1]等等。
创建一个子进程,调用exec执行命令。
父进程(即shell命令解释器)根据命令是在前台还是后台运行,决定是否调用waitpid()。然后进入下一次循环。
第2步:加入内部命令cd、exit。
学员需要完成的内容如下:
以第1步为基础,在分析完命令行输入后,看输入的命令arg[0]是不是“exit”或者“cd”,如果是的话,在执行创建子进程去执行这个命令之前就做为内部命令执行。
exit命令的实现只要打印一句话“Bye bye!”,然后释放前面分配的内存空间,然后退出即可。
cd命令的实现用到函数chdir(arg[1]),它用来改变当前工作目录。
第3步:程序的实现分别放在几个文件中,引入头文件的概念。引入重定向和管道函数,但不用具体实现这两个函数。
学员需要完成的内容如下:
引入头文件,把公共的变量和函数放在头文件中,注意防止头文件被重复包含。
处理用户输入的命令行中包含重定向符号和管道符号的情况。使用函数redirect()和my_pipe()处理重定向和管道,这两个函数的实现放在一个单独的文件中,不用具体实现这两个函数。
第4步:引and not入环境变量配置文件mysh_profile,读取环境变量,判断文件是否存在,若存在,执行命令,否则打印“comm found”。
学员需要完成的内容如下:
创建一个环境变量配置文件,里面的内容是一行PATH环境变量如下:PATH=/bin:/sbin:/usr/bin:/usr/sbin
创建函数init_environ(),读取环境变量到数组。
创建函数is_founded(),查找文件,看文件是否存在。
第5步:实现重定向功能。
学员需要完成的内容如下:
在redirect.c文件中实现redirect()函数。
第6步:实现管道功能
学员需要完成的内容如下:
在pipe.c文件中实现my_pipe()函数。
第7步:实现历史记录命令history
学员需要完成的内容如下:
在头文件mysh.h中增加表示历史记录的循环数组的数据类型,并定义相应变量。
在history.c中实现函数add_history()和history_cmd()。
在main.c中,分别在管道、重定向、内部命令、普通命令执行前,把命令行内容加入到命令历史记录循环数组中。
第8步:实现后台作业队列,加入内部命令jobs、bg、fg命令。
#include
#include
#include
#include
int main(void)
{
int i,status,s;
pid_t pid1;
char a[100];
char *arg[100], *b="(char *)0";
while(1)
{
printf("---->");
fgets(a,100,stdin);
s=sizeof(a);
arg[0]=strtok(a," \n");
for(i=0;arg!=NULL;i++)
{
arg[i+1]=strtok(NULL," \n");
}
arg[i+1]=b;
if(strcmp(arg[0],"exit")==0)
{
printf("Bye bye!\n");
exit(0);
}else if(strcmp(arg[0],"cd")==0)
{
chdir(arg[1]);
// break; * how to skip zhis functino only?
}else
{
if((pid1=fork()) < 0)
{
perror("fork");
exit(1);
}
if(pid1==0)
{
execvp(arg[0],arg);
exit(-1);
}
wait(&status);
}
}
return 0;
}