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

📄 myshell.c

📁 应用UNIX的fork()等系统调用
💻 C
字号:
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <dirent.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <string.h>#define BUFFERSIZE 200char buffer[BUFFERSIZE];void main(){	char * path,* input,*entering,* p,* arg[BUFFERSIZE];	char lc_char;	int li_inputlen,i,j,k,l,is_back,is_bj,pid,status,flag;	flag=1;	while(flag) 	{		is_bj = 0;
	   is_back = 0;		path = get_current_dir_name();		printf("%s > $", path);		/* 开始获取输入 */	   li_inputlen=0;		lc_char = getchar();		while (lc_char != '\n' && li_inputlen < BUFFERSIZE) 		{	    	buffer[li_inputlen ++] = lc_char;	    	lc_char = getchar();		}			/* 命令超长处理*/		if(li_inputlen > BUFFERSIZE) 		{			printf("Your command too long ! Please reenter your command !\n");	   	li_inputlen = 0;     /* Reset */	     	continue;		}		else	  		buffer[li_inputlen] = '\0'; /*加上串结束符,形成字符串*/		entering = (char *)malloc(sizeof(char) * (li_inputlen + 1));		strcpy(entering, buffer);				p=entering;		l=0;		input = (char *)malloc(sizeof(char) * (li_inputlen + 1));		while(1)		{				if(*p!=';'&&*p!='\0')				input[l++]=*p;			else			{				input[l]='\0';				for( i = 0, j=0,k=0; i<=li_inputlen; i ++) 				{					if (input[i] == '<' || input[i] == '>' || input[i] =='|')					{
						if (input[i] == '|')
			  				pipel(input,li_inputlen); 
						else
			  				redirect(input,li_inputlen);
					  	is_bj = 1;						break;
					}					if(input[i]== ' ' || input[i] == '\t' || input[i] == '\0') 					{			   		if(j == 0) /*这个条件可以略去连在一起的多个空格或者TAB */				      	continue;			   		else 						{			       		buffer[j ++] = '\0';			       		arg[k] = (char *)malloc(sizeof(char) * j);			     				  /* 将指令或参数从缓存拷贝到arg中*/			       		strcpy(arg[k], buffer);							/* 将命令从缓存拷贝到input中*/					 		j = 0;  /* 准备去下一个参数*/			       		k ++;			   	 		}					}					else 					{       /* 如果字符串最后是 '&',则置后台运行标记为 1 */		    			if(input[i]== '&' && input[i + 1] == '\0')				 		{			      		is_back = 1;		      			continue;						}						buffer[j ++] = input[i];					}				}				free(input);   /* 释放空间*/		   				if(strcmp(arg[0], "exit") == 0)				{					printf("bye-bye\n");					flag=0;					break;				}	   		if(is_bj == 0) 				{					/* 非管道、重定向指令*/									/* 在使用exec执行命令的时候,最后的参数必须是NULL指针,所以将最后一个参数置成空值*/					arg[k] = (char *)malloc(sizeof(char));					arg[k ++] = (char *)0;					/* 判断指令arg[0]是否存在*/					if(is_fileexist(arg[0]) == -1) 					{			    		printf("This is command is not founded ?!\n");			    		for(i = 0; i < k; i ++)			        	free(arg[i]);			    		break;					}					if((pid = fork()) == 0)      /*子进程*/			     		execv(buffer, arg);					else                     /*父进程*/			   		if(is_back == 0)        /* 并非后台执行指令*/							waitpid(pid, &status, 0);			   		/* 释放申请的空间*/			   		for(i = 0; i < k; i ++) 					  		free(arg[i]);				}									l=0;								if(*p=='\0')					break;							}				p++;					}	}}int is_fileexist(char * comm){	char * path, * p;	int i;	i = 0;	/* 使用getenv函数来获取系统环境变量,用参数PATH表示获取路径*/	path = getenv("PATH");	p = path;	while(*p != '\0') 	{   		/* 路径列表使用":"来分隔路径*/   	if(*p !=':')	  		buffer[i ++] = *p;		else 		{       	buffer[i ++] = '/';       	buffer[i] = '\0';      			 /* 将指令和路径合成,形成pathname,并使用access函数来判断该文件是否存在*/       	strcat(buffer, comm);       	if(access(buffer, F_OK) == 0)     /* 文件被找到*/             return 0;       	else                          /* 继续寻找其他路径*/             i = 0;    			}    		p ++;		}	return -1;}int redirect(char *in,int len)
{
    char *argv[30],*filename[2];
    pid_t pid;
    int i,j,k,fd_in,fd_out,is_in = -1,is_out = -1,num = 0;
    int is_back = 0,status=0;

/*这里是重定向的命令解析过程,其中filename用于存放重定向文件,
 *is_in, is_out分别是输入重定向标记和输出重定向标记*/
    for (i = 0,j = 0,k = 0;i <= len;i++){
        if (in[i]==' '||in[i]=='\t'||in[i]=='\0'||in[i] =='<'||in[i]=='>'){
            if (in[i] == '>' || in[i] == '<'){
/*重定向指令最多'<','>'各出现一次,因此num最大为2,
 *否则认为命令输入错误*/
                if (num < 3){
	            num ++;
	            if (in[i] == '<') 
	                is_in = num - 1;
	            else
	                is_out = num - 1;
				
		   /*处理命令和重定向符号相连的情况,比如ls>a*/
		    if (j > 0 && num == 1)	{
		        buffer[j++] = '\0';
		        argv[k] = (char *) malloc(sizeof(char)*j);
		        strcpy(argv[k],buffer);
		        k++;
		        j = 0;
                    }
                }
	        else{
	            printf("The format is error!\n");
	            return -1;
	        }
            }	 
	    if (j == 0) 
	        continue;
	    else{
		buffer[j++] = '\0';
		/*尚未遇到重定向符号,字符串是命令或参数*/
        	if (num == 0){
		    argv[k] = (char *) malloc(sizeof(char)*j);
		    strcpy(argv[k],buffer);
		    k++;
		}
		/*是重定向后符号的字符串,是文件名*/
		else{
		    filename[status] = (char *) malloc(sizeof(char)*j);
		    strcpy(filename[status++],buffer);
		}
		j = 0;	/*initate*/
            }
        } 
        else{	
	    if (in[i] == '&' && in[i+1] == '\0'){
	        is_back = 1;
	        continue;
	    }
	    buffer[j++] = in[i];
        }	
    }

    argv[k] = (char *) 0;

    if (is_fileexist(argv[0]) == -1 ){
        printf("This command is not founded!\n");
        for(i=0;i<k;i++)
            free(argv[i]);
        return 0;
    }

    if ((pid = fork()) ==0){
		/*存在输出重定向*/
        if (is_out != -1)
            if((fd_out=open(filename[is_out],O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR))==-1){ 
                printf("Open out %s Error\n",filename[is_out]); 
                return -1; 
            } 

		/*存在输入重定向*/
        if (is_in != -1)
            if((fd_in=open(filename[is_in],O_RDONLY,S_IRUSR|S_IWUSR))==-1){ 
                printf("Open in %s Error\n",filename[is_out]); 
                return -1; 
            } 

        if (is_out != -1)
		 /*使用dup2函数将标准输出重定向到fd_out上,dup2(int oldfd,int newfd)实现的
   	  *是把oldfd所指的文件描述符复制到newfd。若newfd为一已打开的文件描述词,
         *则newfd所指的文件会先被关闭,dup2复制的文件描述词与原来的文件描述词
         *共享各种文件状态*/
            if(dup2(fd_out,STDOUT_FILENO)==-1){ 
                printf("Redirect Standard Out Error\n"); 
                exit(1); 
            } 

    	if (is_in != -1)
       	    if(dup2(fd_in,STDIN_FILENO)==-1){ 
                printf("Redirect Standard Out Error\n"); 
                exit(1); 
       	    } 
        execv(buffer,argv);
    }
    else
        if (is_back == 0)  /*run on the TOP*/
            waitpid(pid,&status,0);

    for (i=0;i<k;i++)
        free(argv[i]);

    if (is_in != -1){
        free(filename[is_in]);
        close(fd_in);
    }
    if (is_out != -1){
        free(filename[is_out]);
        close(fd_out);
    }
    return 0;
}


int pipel(char *input,int len)
{
  char *argv[2][30];
  int i,j,k,count,is_back = 0;
  int li_comm = 0,fd[2],fpip[2];
  char lc_char,lc_end[1];
  pid_t child1,child2;

/*管道的命令解析过程*/
  for (i = 0,j = 0,k = 0;i <= len;i++){
    if (input[i]== ' ' || input[i] == '\t' || input[i] == '\0' || input[i] == '|'){
      if (input[i] == '|' ) /*管道符号*/
{
        if (j > 0)
{
          buffer[j++] = '\0';
         /*因为管道连接的是两个指令,所以用二维数组指针来存放命令和参数,li_comm是表示第几个指令*/
          argv[li_comm][k] = (char *) malloc(sizeof(char)*j);
          strcpy(argv[li_comm][k++],buffer);
}
        argv[li_comm][k++] = (char *) 0;
        /*遇到管道符,第一个指令完毕,开始准备接受第二个指令*/
        li_comm++; 
        count = k;
        k=0;j=0;
}
      if (j == 0)
        continue;
      else
 {
        buffer[j++] = '\0';
        argv[li_comm][k] = (char *) malloc(sizeof(char)*j);
        strcpy(argv[li_comm][k],buffer);
        k++;
}
      j = 0;	/*initate*/
 }
    else{	
      if (input[i] == '&' && input[i+1] == '\0'){
        is_back = 1;
        continue;
 }
      buffer[j++] = input[i];
 }
 }
  argv[li_comm][k++] = (char *) 0;

  if (is_fileexist(argv[0][0]) == -1 ){
    printf("This first command is not found!\n");
    for(i=0;i<count;i++)
      free(argv[0][i]);
    return 0;
  }
/*指令解析结束*/

/*建立管道*/
  if (pipe(fd) == -1 ){
    printf("open pipe error!\n");
    return -1;
  }

/*创建第一个子进程执行管道符前的指令,并将输出写到管道*/
  if ((child1 = fork()) ==0){
/*关闭读端*/
    close(fd[0]);
    if (fd[1] != STDOUT_FILENO){
   /*将标准输出重定向到管道的写入端,这样该子进程的输出就写入了管道*/
      if (dup2(fd[1],STDOUT_FILENO) == -1){
        printf("Redirect Standard Out Error\n");
        return -1;
      }
   /*关闭写入端*/
      close(fd[1]);
    }
    execv(buffer,argv[0]);
  }
  else{           /*父进程*/
/*先要等待写入管道的进程结束*/
    waitpid(child1,&li_comm,0);	
/*然后我们必须写入一个结束标记,告诉读管道进程数据到这里就完了*/
    lc_end[0] = 0x1a;
    write(fd[1],lc_end,1);
    close(fd[1]);

    if (is_fileexist(argv[1][0]) == -1 ){
      printf("This command is not founded!\n");
      for(i=0;i<k;i++)
      free(argv[1][i]);
      return 0;
    }
   
/*创建第二个进程执行管道符后的指令,并从管道读输入流 */
    if ((child2 = fork()) == 0){
      if (fd[0] != STDIN_FILENO){
   /*将标准输入重定向到管道读入端*/
        if(dup2(fd[0],STDIN_FILENO) == -1){
          printf("Redirect Standard In Error!\n");
          return -1;
        }
        close(fd[0]);
      }
      execv(buffer,argv[1]);
    }
    else     /*父进程*/
      if (is_back == 0)
        waitpid(child2,NULL,0);
  }
  for (i=0;i<count;i++)
    free(argv[0][i]);
  for (i=0;i<k;i++)
    free(argv[1][i]);
  return 0;
}

⌨️ 快捷键说明

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