⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ysh.c

📁 Linux下实现shell的部分功能
💻 C
字号:
#include "ysh.h"
#include "extern.h"

char *envpath[10],buf[BUFSIZE],*input=NULL;
pid_t pid1=0;
int sig_flag=0,sig_z=0,history_number;
ENV_HISTORY envhis;
NODE *head,*end;

int main()
{
	init_environ(); /*初始化环境变量,将查找路径至于envpath[]中,初始化history,和jobs的头尾指针*/
	while (1)
	{
		char c,*arg[20];
		int i=0,j=0,k=0,is_pr=0,is_bg=0,input_len=0,path,pid=0,status=0;
		history_number=envhis.end;

/********************设置signal信号********************/
		struct sigaction action;
		action.sa_sigaction=del_node;
		sigfillset(&action.sa_mask);
		action.sa_flags=SA_SIGINFO;
		sigaction(SIGCHLD,&action,NULL);
		// signal(SIGTSTP,ctrl_z);
		signal(SIGTSTP,up_history);

/********************打印提示符************************/
		path=get_current_dir_name();
		printf("ysh@%s> ",path);

/********************获取用户输入**********************/
		while ((c=getchar())==' ' || c=='\t'|| c==EOF)
			; /*跳过空格等无用信息*/
		while (c!='\n') {
			buf[input_len++]=c;
			c=getchar();
		}
		buf[input_len]='\0'; /*加上串结束符*/
		/*分配动态存储空间,将命令从缓存拷贝到input中*/
		input=(char *) malloc(sizeof(char)*(input_len+1));
		strcpy(input,buf);

/********************解析指令**************************/
		/*管道和重定向命令单独处理*/
		for (i=0,j=0,k=0;i<=input_len;i++){
			if (input[i]=='<' || input[i]=='>' ||input[i]=='|'){
				if (input[i]=='|'){
					pipel(input,input_len); /*管道命令*/
					add_history(input);
					free(input);
				}else{
					redirect(input,input_len); /*重定向命令*/
					add_history(input);
					free(input);
				}
				is_pr=1;
				break;
			}
		}

/********************普通命令**************************/
		if (is_pr==1) continue;
		for (i=0,j=0,k=0;i<=input_len;i++){
			if (input[i]==' ' || input[i]=='\0'){
				if (j==0) /*这个条件略去连在一起的多个空格*/
					continue;
				else{
					buf[j++]='\0';
					arg[k]=(char *)
					malloc(sizeof(char)*j);
					strcpy(arg[k++],buf); /*将指令或参数拷到arg中*/
					j=0; /*准备取下一参数*/
				}
			}else{
				/*如果字符串最后是“&”,将后台命令标志置一*/
				if (input[i]=='&' && input[i+1]=='\0'){
					is_bg=1;
					continue;
				}
				buf[j++]=input[i];
			}
		}

/********************内部命令的处理*********************/
		/*exit命令,退出*/
		if (strcmp(arg[0],"exit")==0) {
			add_history(input);
			printf("Bye bye!\n");
			free(input);
			break;
		}
		/*history命令,显示history数组中保存的历史命令*/
		if (strcmp(arg[0],"history")==0) { 
			add_history(input);
			history_cmd();
			free(input);
			continue;
		}
		/*cd命令,改变当前路径*/
		if (strcmp(arg[0],"cd")==0) {
			add_history(input);
			for (i=3,j=0;i<=input_len;i++) /*获取路径*/
				buf[j++]=input[i];
			buf[j]='\0';
			arg[1]=(char *) malloc(sizeof(char)*j);
			strcpy(arg[1],buf);/*将路径保存到arg[1]中*/
			cd_cmd(arg[1]);/*cd_cmd()函数,改变路径到指定路径*/
			free(input);
			continue;
		}
		/*jobs命令,显示现有工作*/
		if (strcmp(arg[0],"jobs")==0) {
			add_history(input);
			jobs_cmd(); /*jobs_cmd()函数,遍历链表,显示所有工作*/
			free(input);			continue;
		}
		/*bg命令,将作业放到后台执行*/
		if (strcmp(arg[0],"bg")==0) {
			add_history(input);
			/*获取制定的作业号,作业号在%后*/
			for (i=0;i<=input_len;i++) {
				if (input[i]=='%')
					break;
			}
			i++;
			for (;i<=input_len;i++)
				buf[j++]=input[i];
			buf[j]='\0';
			arg[1]=(char *) malloc(sizeof(char)*j);
			strcpy(arg[1],buf); /*将作业号保存在arg[1]中*/
			bg_cmd(atoi(arg[1])); /*bg_cmd命令,将指定作业放到后台运行*/
			free(input);
			continue;
		}
		/*fg命令,将作业放到前台执行*/
		if (strcmp(arg[0],"fg")==0) {
			add_history(input);
			/*获取制定的作业号,作业号在%后*/
			for (i=0;i<=input_len;i++) {
				if (input[i]=='%')
					break;
			}
			i++;
			for (;i<=input_len;i++)
				buf[j++]=input[i];
			buf[j]='\0';
			arg[1]=(char *) malloc(sizeof(char)*j);
			strcpy(arg[1],buf); /*将作业号保存在arg[1]中*/
			fg_cmd(atoi(arg[1])); /*fg_cmd命令,将指定作业放到后台运行*/
			free(input);
			continue;
		}

/********************寻找命令文件***********************/
		if (is_pr==0){/*非管道、重定向命令*/
			/*在使用exec执行命令时,最后的参数必须是NULL指针,所以将其置空*/
			arg[k]=(char *) malloc(sizeof(char));
			arg[k]=NULL;
			if (is_founded(arg[0])==0){ /*查找arg[0]中的命令是否存在*/
				printf("This command is not founded!\n");
				for (i=0;i<=k;i++)
					free (arg[i]);
				continue;
			}
		}
		add_history(input);

/********************执行命令***************************/
		if ((pid=fork())==0){ /*子进程*/
			if (is_bg==1) /*若为后台命令,等待父进程增加节点*/
				while (sig_flag==0) /*若sig_flag==0,等待父进程完成增加节点*/
					/*等待父进程SIGUSR1信号,表示节点已加到链表中*/
					signal(SIGUSR1,setflag); /*收到信号,setflag函数将sig_flag置一,以跳出循环*/					sig_flag=0; /*置零,为下一命令作准备*/
			execv(buf,arg); /*执行命令*/
		}else { /*父进程*/
			pid1=pid; /*保存子进程进程号*/
			if (is_bg==1) { /*后台命令*/
				add_node(input,pid1);/*增加节点*/
				kill(pid,SIGUSR1); /*向子进程发信号,表示节点已加进链表*/
				pid1=0; /*pid1置零,为下一命令作准备*/
			}
			if (is_bg==0) /*前台命令*/
				waitpid(pid,&status,0);
		}
		if (is_bg==1)
			sleep(1); /*等待命令(如:ls &)输出后,再打印Shell提示符*/
		for (i=0;i<k;i++) /*释放空间*/
			free (arg[i]);
		free(input);
	}
	return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -