Linux下模拟实现自己的mini_shell,支持简单命令、重定向、管道。

一、shell是什么。
Linux是一款操作系统,我们称之为核心(Kernel),但我们一般用户不能直接使用Kernel,而是通过Kernel的外壳程序,也就是shell,来与Kernel沟通,从技术角度讲,shell的最简单定义就是命令行解释器。
二、思路分析
下面来简单介绍一下实现思路,首先使用fork系统调用,创建子进程,在子进程中进行程序替换,使用exec系列函数(主要使用ecexvp函数)实现,让后让父进程阻塞等待,避免出现孤儿进程。细节是,首先获取用户输入,把其中的空格替换为’\0’,让后保存在一个字符指针数组中,让后作为参数传入execvp函数,进行程序替换。
重定向的实现,获取用户输入后,检测其中是否有>或者>>,判断是否有重定向,在把重定向的符号替换为’\0’,让后获取重定向符号后面的要重定向到那个文件(这里使用file指代该文件), 在找到>符号后,还可以向后在判断一个字符,判断是输出重定向还是追加重定向。打开文件后,使用dup2系统调用把当前进程打开的文件和进程默认打开的标准输出交换,也就是让该文件的描述符换到标准输出上,这样该进程中所有的向标准输出的东西就都会被写入到该文件(即file)中去。
管道的实现,首先,我们先建立一个共识,命令行中的管道的功能就是连接命令行的中的命令的。有了这个共识之后,我们就可以着手在命令行中添加管道功能了。首先,对用户输入解析,判断其中是否有’|’,然后把其中所有’|‘都替换为’\0’, 在前面的基础上,把所有的命令都按’\0’分开的,存入到一个队列中,让后在do_fork函数中,循环拿出队列中的元素,创建子进程进行程序替换,直到队列为空。

三、代码展示

#include<iostream>
	#include<string.h>
	#include<stdio.h>
	#include<sys/types.h>
	#include<sys/stat.h>
	#include<fcntl.h>
	#include<unistd.h>
	#include<sys/wait.h>
	#include<queue>
	//简单的mini_shell支持重定向、管道和一些简单命令
	#define MAX 1024
	#define NUM 30
	char cmd[MAX];
	char* argv[NUM];
	std::queue<char*> q;
	
	//打印命令行前面的一堆东东
	void do_display(){
	    std::cout<<"[xxx@localhost shell]$";
	    fgets(cmd, MAX, stdin);
	    cmd[strlen(cmd)-1] = '\0';
	}
	
	//命令行解析
	void do_analy(char* pcmd){
	    int i = 0;
	    char* p = NULL;//使用指针是一定要初始化
	    p = strtok(pcmd, " ");
	    argv[i] = p;
	    i++;
	    while(1){
	        p = strtok(NULL, " ");
	        if(p == NULL){
	            argv[i] = NULL;
	            break;
	        }
	        argv[i] = p;
	        i++;
	    }
	}
	
	std::queue<char*>& do_pipe_num(){
	    while(!q.empty()){
	        q.pop();
	    }
	    char* ptr = cmd;
	    q.push(ptr);
	    while(*ptr != '\0'){
	        if(*ptr == '|'){
	            *ptr = '\0';
	            ptr++;
	            while(*ptr == ' ')
	            {
	                ptr++;
	            }
	            q.push(ptr);
	        }
	        ptr++;
	    }
	    return q;
	}
	//重定向函数
	void do_diredict(char* t){
	    char* ptr = t;
	    char* file = NULL;//这里file一定初始化为空指针,不然会吧命令行输出重定向到一个名字为?的文件中,这个问题坑了我好久。所以以后定义变量一定要记得初始化。
	    int fd;
	    while(*ptr != '\0'){
	        if(*ptr == '>'){
	            *ptr = '\0';
	            ptr++;
	
	        while(*ptr == ' '){
	            ptr++;
	        }
	
	        file = ptr;
	        while((*ptr != ' ') && (*ptr != '\0')){
	            ptr++;
	        }
	        }
	        ptr++;
	    }
	    fd = open(file, O_CREAT|O_WRONLY, 0644);
	    dup2(fd, 1);
	    close(fd);
	}
	
	//程序替换
	void do_fork(std::queue<char*>& q){
	
	    while(!q.empty()){
	    pid_t id = fork();
	    if(id < 0){
	        std::cout<<"fork error"<<std::endl;
	    }
	
	    else if(id == 0){
	        char* tmp = q.front();
	        do_diredict(tmp);
	        do_analy(tmp);
	        execvp(argv[0], argv);
	    }
	
	    else{
	        waitpid(id,NULL, 0);
	    }
	    q.pop();
	    }
	}
	
	
	int main(){
	    while(1){
	        do_display();
	        std::queue<char*>& q_pipe = do_pipe_num();
	        //do_diredict();
	        //do_analy();
	        do_fork(q_pipe);
	        sleep(1);
	    }
	    return 0;
	}

四、效果展示
在这里插入图片描述
在这里插入图片描述

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值