C语言实现一个精简的shell

仅供参考

短学期作业之一,放上来做个纪念:

/***************************************************************************
*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){
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值