仅供参考
短学期作业之一,放上来做个纪念:
/***************************************************************************
*Project Name: myshell
*Description: a reduced shell program implemented by C
*Auther:lishichengyan
*Student ID:omitted
*Last Modified: 2017.08.03
***************************************************************************/
/*必要的头文件包含*/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<memory.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/stat.h>
#include<sys/param.h>
#include<pwd.h>
#include<errno.h>
#include<time.h>
#include<fcntl.h>
#include<dirent.h>
#include<signal.h>
/*和长度有关的宏定义*/
#define MAX_LINE 80//最大命令长度
#define MAX_NAME_LEN 100//最大用户名长度
#define MAX_PATH_LEN 1000//最大路径长度
/*全局变量申明*/
extern char **environ;//必须用extern申明,否则会报错
char *cmd_array[MAX_LINE/2+1];//保存命令输入,就是原框架的char* args[]
int pipe_fd[2];//和管道有关的数组,作为pipe()的参数
int cmd_cnt;//命令中字符串的个数
/*老师框架里的函数(有改动)*/
void readcommand();//读取用户输入
int is_internal_cmd();//处理内部命令
int is_pipe();//分析管道命令
void do_redirection();//分析重定向,对内部命令无效
/*自己定义的函数*/
void welcome();//打印欢迎信息,带有颜色
void printprompt();//打印提示符,必须包含当前路径名
int getcommandlen();//计算命令长度
void do_pipe(int pos);//执行管道命令
void run_external_cmd(int pos);//执行外部命令
int is_bg_cmd();//判断是否有后台运行符号&
void myquit();//quit,退出myshell
void myexit();//exit,直接退出
void myclr();//clr,和BatchShell下的clear一样
void print_continue_info();//打印"continue"相关信息
void mypwd();//pwd,打印当前工作目录
void myecho();//echo,必须支持重定向
void myecho_redirect();//带重定向的echo
void mytime();//time,和"date"类似
void myenviron();//environ,和env一样,必须支持重定向
void myenviron_redirect();//带重定向的environ
void mycd();//cd,切换到某个目录
void myhelp();//help,必须支持重定向
void myhelp_redirect();//带有重定向的help
void print_manual();//打印用户手册,是myhelp()的子函数
void print_cmdinfo(char* cmdname);//打印每个命令的帮助信息,是myhelp()的子函数
void myexec();//exec,开启一个新进程并替换当前进程
void mytest();//test,检查文件类型,支持-l,-b,-c,-d四个选项
void myumask();//umask,查看默认的umask值或者重置umask
void myjobs();//jobs,查看正在运行的=进程
void myfg(pid_t pid);//fg,切换进程到前台
void mybg(pid_t pid);//bg,切换进程到后台
void mybatch();//实现命令批处理,一次性执行保存在文件里的命令
void mydir();//dir,显示当前目录下的所有文件
void mydir_redirect();//带有重定向的dir
/*老师所给函数的实现(框架有调整)*/
/*实现顺序和定义顺序相同*/
void readcommand(){
//这个函数用来读取用户输入
int cnt=0;//记录cmd_array[]中字符串的个数
char str[MAX_LINE];
char* helper;
memset(cmd_array,0,MAX_LINE/2+1);//每次必须清空!
fgets(str,MAX_LINE,stdin);//用fgets代替gets,因为gets不检查溢出,比较危险
if(str[strlen(str)-1]=='\n'){
str[strlen(str)-1]='\0';//fgets会补'\n',这里必须把'\n'替换成'\0'
}
helper=strtok(str," ");//用空格分割这个命令
while(helper!=NULL){//将分割后得到的结果写进cmd_array
cmd_array[cnt]=(char*)malloc(sizeof(*helper));
strcpy(cmd_array[cnt++],helper);//注意:即便直接回车cmd_cnt也是1
helper=strtok(NULL," ");
}
cmd_cnt=cnt;//cmd_cnt的值就是cnt的值
}
int is_internal_cmd(){
//这个函数用来解析内部命令
//根据不同的结果来调用不同函数来达到目的
if(cmd_array[0]==NULL){//如果没有命令(只是回车)
return 0;//返回0使得主函数的continue不执行
}
else if(strcmp(cmd_array[0],"quit")==0){//quit,退出之前有“Thank you...”提示信息
myquit();
}
else if(strcmp(cmd_array[0],"exit")==0){//exit,直接退出
myexit();
}
else if(strcmp(cmd_array[0],"clr")==0){//clr,清屏
myclr();
return 1;
}
else if(strcmp(cmd_array[0],"continue")==0){//continue命令,它只在循环里有效
print_continue_info();
return 1;
}
else if(strcmp(cmd_array[0],"pwd")==0){//pwd,打印当前工作目录
mypwd();
return 1;
}
else if(strcmp(cmd_array[0],"echo")==0){//echo
for(int i=1;i<cmd_cnt;i++){//从第二个字符串开始分析
if(strcmp(cmd_array[i],">")==0||strcmp(cmd_array[i],">>")==0){//如果有重定向符号
myecho_redirect();//调用带有重定向的echo
return 1;
}
}
myecho();//如果没有重定向,直接echo
return 1;
}
else if(strcmp(cmd_array[0],"time")==0){//time,显示当前时间,和date命令相似
mytime();
return 1;
}
else if(strcmp(cmd_array[0],"environ")==0){//environ
if(cmd_array[1]!=NULL&&(strcmp(cmd_array[1],">")==0||strcmp(cmd_array[1],">>")==0)){//带有重定向
myenviron_redirect();//调用带有重定向的environ
return 1;
}
else{
myenviron();//没有重定向
return 1;
}
}
else if(strcmp(cmd_array[0],"cd")==0){//cd,切换目录
mycd();
return 1;
}
else if(strcmp(cmd_array[0],"help")==0){//help
if(cmd_array[1]!=NULL&&(strcmp(cmd_array[1],">")==0||strcmp(cmd_array[1],">>")==0)){//带有重定向
myhelp_redirect();//注意:格式是 "help > filename"或者"help >>filename"
return 1;
}
else{
myhelp();//没有重定向
return 1;
}
}
else if(strcmp(cmd_array[0],"exec")==0){//exec,开启一个新进程替换当前进程
myexec();
return 1;
}
else if(strcmp(cmd_array[0],"test")==0){//test,用来查看文件属性,支持[-l],[-d],[-c],[-b]四个选项
mytest();
return 1;
}
else if(strcmp(cmd_array[0],"umask")==0){//umask,查看或者设置umask值
myumask();
return 1;
}
else if(strcmp(cmd_array[0],"jobs")==0){//jobs,查看运行的进程
myjobs();
return 1;
}
else if(strcmp(cmd_array[0],"fg")==0){//fg,将进程切换到前台
pid_t pid;
if(cmd_array[1]!=NULL){
pid=atoi(cmd_array[1]);//用atoi转换,获取pid
}
else{//如果只有一个fg
printf("myshell: fg: no job assigned\n");//打印提示信息
return 1;
}
myfg(pid);
return 1;
}
else if(strcmp(cmd_array[0],"bg")==0){
pid_t pid;
if(cmd_array[1]!=NULL){
pid=atoi(cmd_array[1]);//用atoi转换,获取pid
}
else{//只有一个bg
printf("myshell: bg: no job assigned\n");//打印提示信息
return 1;
}
mybg(pid);
return 1;
}
else if(strcmp(cmd_array[0],"myshell")==0){
if(cmd_cnt==1){//只有一个myshell命令
printf("myshell: myshell: too few arguments\n");//打印提示信息
return 1;
}
else if(cmd_cnt==2){//输入格式是:myshell [filename]
mybatch();
return 1;
}
else{//参数过多的情况
printf("myshell: myshell: too many arguments\n");
return 1;
}
}
else if(strcmp(cmd_array[0],"dir")==0){//dir
if(cmd_array[1]!=NULL&&(strcmp(cmd_array[1],">")==0||strcmp(cmd_array[1],">>")==0)){//有重定向,格式是: dir > filename或者dir >> filename
mydir_redirect();//调用带有重定向的dir
return 1;
}
else{//没有重定向
mydir();
return 1;
}
}
else if(strcmp(cmd_array[0],"set")==0){//I'll try latter
printf("myshell: set: not supported currently\n");
return 1;
}
else if(strcmp(cmd_array[0],"unset")==0){//I'll try latter
printf("myshell: unset: not supported currently\n");
return 1;
}
else if(strcmp(cmd_array[0],"shift")==0){//I'll try latter
printf("myshell: shift: not supported currently\n");
return 1;
}
else{
return 0;//返回0使得主函数的continue不执行
}
}
int is_pipe(){
for(int i=1;i<cmd_cnt;i++){//从第二个字符串开始分析
if(cmd_array[i]!=NULL&&strcmp(cmd_array[i],"|")==0){