手撸一个linux的交互式shell程序,可实现输出重定向以及管道功能(附源代码)

功能如下:
(1)显示命令提示符%;
(2)获取用户输入指令;解析指令;寻找命令文件,执行指令;
(3)前一个命令完成后才继续显示命令提示符%,等待用户输入下一条命令;
(3)如果输入“exit”或“logout”,则退出shell.
(4)允许命令参数间有多个空格,也允许命令前后有空格
(5)支持输出重定向和管道功能。

void _spilt(char **argv,char *file,char **file_argv,char** pipeO,char** pipeI,char *cmdline)
/** 解析从命令行输入的字符串*/
void eval(char* cmdline)
/**执行命令*/

重定向实现:利用dup去改变标准输出文件描述符指向的文件

//核心代码:file是重定向输出的文件,即command > file
fd = open(file,O_WRONLY|O_CREAT|O_TRUNC,0777);
close(1);
dup(fd);

管道实现:利用pipe这个缓冲区(实际上可以当成是文件),然后利用dup改变标准输入和标准输出文件描述符指向的文件

//核心代码:改变标准输入和标准输出文件描述符指向的地方
pipe(pipe_fd);
dup2(pipe_fd[1],1);
dup2(pipe_fd[0],0);

程序所包含的知识:dup和文件描述符,pipe以及exec族(这里用execvp函数实现)还有fork,最后就是解析字符串了

源代码:

#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 100
#define LEN 10
int isCDX = 0;
int isPipe = 0;
void _spilt(char **argv,char *file,char **file_argv,char** pipeO,char** pipeI,char *cmdline){
	int i = 0, j = 0, cdx_argv, temp,pipe1,pipe2;
	int k, len;
	len = strlen(cmdline);
    isCDX = 0;
    isPipe = 0;
	//解析shell
	for(k = 0;k < len; k++){
	    if(cmdline[k] == ' '&& k == 0) continue; //去掉首个空格
		else if(cmdline[k] == ' '&& cmdline[k-1] == ' ')continue; //去掉多个空格
		else if(cmdline[k] == ' '){
		    //字符串尾
			argv[i][j] = '\0';
			j = 0;
			i++;
		}else if(cmdline[k] == '\n' && k > 0 && cmdline[k-1] == ' '){
		    //字符串解析完多个空格后回车
			argv[i] = NULL;
		}else if(cmdline[k] == '\n' && k == 0){
		    //首个就是回车
            argv == NULL;         
		}else if(cmdline[k] == '\n'){
		    //字符串解析完成
			argv[i][j] = '\0';
			i++;
			argv[i] = NULL;
		}else{
		   //其他情况复制字符
			argv[i][j] = cmdline[k];
			j++;
		}
			
	}
	//查找是否为重定向
	for(temp = 0; temp <= i; temp++){
		if(argv[temp] != NULL){
			if(strcmp(argv[temp],">") == 0){
				isCDX = 1;
				strcpy(file,argv[temp+1]);
				
				for(cdx_argv = 0; cdx_argv < temp; cdx_argv++){
				    file_argv[cdx_argv] = (char *)malloc(sizeof(char) * MAXLINE);
					strcpy(file_argv[cdx_argv],argv[cdx_argv]);
				}
				file_argv[cdx_argv] = (char *)malloc(sizeof(char) * MAXLINE);
				file_argv[cdx_argv] = NULL;
				break;
			}else continue;
		}
	}
	if(isCDX == 1) return;
	
	//查找是否为管道
	for(temp = 0; temp <= i; temp++){
		if(argv[temp] != NULL){
			if(strcmp(argv[temp],"|") == 0){
				isPipe = 1;
				for(pipe1 = 0; pipe1 < temp; pipe1++){
					pipeO[pipe1] = (char *)malloc(sizeof(char) * MAXLINE);
					strcpy(pipeO[pipe1],argv[pipe1]);
				}
				pipeO[pipe1] = (char *)malloc(sizeof(char) * MAXLINE);
				pipeO[pipe1] = NULL;
				temp++;
				for(pipe2 = 0; temp < i; temp++){
					pipeI[pipe2] = (char *)malloc(sizeof(char) * MAXLINE);
					strcpy(pipeI[pipe2],argv[temp]);
					pipe2++;
				}
				pipeI[pipe2] = (char *)malloc(sizeof(char) * MAXLINE);
				pipeI[pipe2] = NULL;				
			}
		}
	}
	 
	
}

void eval(char* cmdline){
    char *argv[LEN];//shell参数
    char  file[LEN];//输出重定向文件
    char *file_argv[LEN];//输出重定向参数
    char *pipeI[LEN];//管道接受方command2
    char *pipeO[LEN];//管道输入方command1
    int i,fd;
    pid_t pid,pipePid;
    int pipe_fd[2];
    for(i = 0; i < LEN; i++){
    	argv[i] = (char *)malloc(sizeof(char) * MAXLINE);
    }
    _spilt(argv,file,file_argv,pipeO,pipeI,cmdline);
    if(argv[0]==NULL){
    	return;
    }else if(strcmp("exit",argv[0]) == 0 || strcmp("logout",argv[0]) == 0){
    	exit(0); 
    }else{
    	if((pid = fork())==0){
    	    // printf("我在子进程里\n");
    	    if( isCDX ){
    	        //输出重定向
    	        // printf("我在重定向里\n");
               fd = open(file,O_WRONLY|O_CREAT|O_TRUNC,0777);
               close(1);
               dup(fd);
               if(execvp(argv[0],file_argv) < 0){
               	 printf("%s:Command not found\n",argv[0]);
               	 exit(0);
               }
    	    	
    	    }else if(isPipe){
    	        	 //管道
    	        	 // printf("我在管道里\n");
    	        	if(pipe(pipe_fd) == -1){
    	               printf("Pipe error\n");
    	               exit(0);
    	            }else{
    	               pipePid = fork();//在子进程里再创建子进程,这样父进程就不会退出了
    	               if(pipePid == 0){
    	                       dup2(pipe_fd[1],1);
    	                       if(execvp(pipeO[0],pipeO) < 0){
    	                            printf("%s:Command not found\n",pipeO[0]);
    	                            exit(0);                			
    	                           }  
    	                }else{
    	                    int status; 
    	                    if(waitpid(pipePid,&status,0) < 0){
    	                    	printf("waitfg : waitpid error\n");
    	                    }
    	                    else{
    	        		    dup2(pipe_fd[0],0);
    	                	  if(execvp(pipeI[0],pipeI) < 0){
    	                		  printf("%s:Command not found\n",pipeI[0]);
    	                		  exit(0);
    	                	    }
    	        		    
    	                   }
    	                }
    	                               	
    	            }
    	    }else{  
    	       //shell
    	       // printf("我在shell里\n");
    		   if(execvp(argv[0],argv) < 0){  
                printf("%s:Command not found\n",argv[0]);
                exit(0);  
    		   }
    	  }
    	}else{
    		int status;
    		if(waitpid(pid,&status,0) < 0){
    			printf("waitfg: waitpid error\n");
    		}else{
    			printf("%d %s",pid,cmdline);
    		}
    	}
    	
    }
    
     return;  
	
}

int main(){

   
    char cmdline[MAXLINE];
    while(1){
    	printf("%%");
    	fgets(cmdline,MAXLINE,stdin);
    	if(feof(stdin)) exit(0);
    	eval(cmdline);
    }
    return 0;
  	
}

测试结果:
手撸一个linux的交互式shell程序,可实现输出重定向以及管道功能(附源代码)_第1张图片

**注意:
转载分享请注明转载处!!!
Allen_ZXJ
如果对你有帮助的话请点个赞再走呗
有什么问题也可以留言咨询噢
**

你可能感兴趣的:(Linux学习,linux,C语言,shell)