在Linux系统c语言实现个人命令解释器(mybash)

关于bash

bash是属于shell程序的一种,即解释命令器的一种。shell不是具体哪一款程序,是一类程序的统称,这些程序只要是能够按照用户的要求去调用操作系统的接口,就可以称之为shell程序。
在这里插入图片描述
通过shell可以将用户与内核联系起来。

我们的bash是怎么实现的

想一想该怎么实现
首先我们先从键盘获取我们需要执行的命令,包括后面的参数,例如:ls -f。然后通过分析键盘获得的数据来进行操作,若输入是合法的命令以及参数,我们fork复制一个进程,通过exce替换/use/bin的进程实现我们命令。

假如我们已经执行了我们的mbash,这时候我们需要通过键盘获取执行命令,怎么做呢?
在这里插入图片描述

需要注意的是,如果我们输入“ls”,buff获取到的实际上是“ls\n”,继而我们需要将“\n”给他清楚掉。

这里我们使用一个get_cmd函数来将我们buff中来自键盘的数据进行拆分。(ARGV来自宏定义为:10)
在这里插入图片描述
在这里插入图片描述
这里使用的是strtok字符串函数,在buff中若是遇到 " " 空格就将字符串拆分,存入到s中。随后再次使用strtok时候第一个参数直接传入NULL,因为strlen函数中内部有一个全局变量来记录上一次切割的位置。

输入结束后呢,就要进行判断我们输入的命令是什么。如果是NULL就继续循环(我们的程序在一个while(1)中运行),如果是exit就退出,如果是cd就使用chdir函数进行当前目录的切换,并且继续循环。
在这里插入图片描述
在这里插入图片描述
随后就是复制一个进程,来对我们从键盘获取的命令进行操作,使用excvp的原因是与excel相比,它可以传入一个数组,继而可以传入多个参数。然后就将子进程切换到我们需要的那个操作了。
在这里插入图片描述
在这里插入图片描述

但是好像又不太对

首先我们加上一个宏定义
至于这个宏定义的作用,我们后面再提

在这里插入图片描述

我们上面操作实现的mybash,方法的实现依然是来自 " /usr/bin "下的程序我们只是通过方法调用了这些程序,而并不是来自我们自己实现。下面就要讲一下怎么真正实现自己的mybash
首先我们改一下bash前面的信息。
在这里插入图片描述
在这里插入图片描述
使用这样一个函数。不仅可以随时更改并显示当前目录,而且有了颜色,更像一个真正的bash
在这里插入图片描述
这里的代码几乎与前面相同没有太多的修改。

然后就是对复制进程代码的修改,这里我们进行了一个判断,如果我们输入的命令开头是" ./ 或者 / ",我们认定需要执行的命令不是一个系统命令,而是我们自己完成的可执行程序。便把这个命令存入path中。
在这里插入图片描述

若它是一个系统命令(执行没有添加所在目录,即没有" ./ 或者 / "),那么我们就去我们自己mybin中寻找这个执行文件,这时候前面提到的PATH宏定义就出来了。这里存放的目录就是存放个人实现执行命令的目录,当我们输入,例:ls 我们就会在该目录下寻找这个可执行文件,并且执行。
在这里,我只实现了个别命令,随后会在末尾贴上代码实现代码。
在这里插入图片描述
这次又使用execv来替换进程,这个首先传入一个目录,并在目录下寻找需要替换掉的进程。
在这里插入图片描述
这样只要我们不断完善自己的mybin就可以实现一个完善的使用的属于自己的命令解释器。

所有的代码

mybash

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/wait.h>
#include<pwd.h>

#define ARGC 10
#define PATH "/home/zyq/Linux/c208/mybash/mybin/"


void printf_info()
{
        char *s = "$";
        int uid = getuid();
        if(uid == 0)
        {
                s="#";
        }
        struct passwd *p = getpwuid(uid);
        if(p == NULL)
        {
                printf("$");
                fflush(stdout);
                return;
        }
        char hostname[128] = {0};
        gethostname(hostname,128);
        char curr_dir[256] = {0};
        getcwd(curr_dir,256);
        printf("\e[1;32m%s@%s\e[0m \e[1;34m%s\e[0m%s",p->pw_name,hostname,curr_dir,s);
        char *get_cmd(char* buff,char* myargv[])
{
        if(buff == NULL|| myargv == NULL)
        {
                return NULL;
        }
        int i =0;
        char * s = strtok(buff," ");
        while(s!=NULL)
        {
                myargv[i++] = s;
                s = strtok(NULL," ");
        }
        return myargv[0];
}
int main()
{
        while(1)
        {
                char path[256] = {0};

                //封装实现 头
                //printf("zyq@localhost:%s  ~$ ",getcwd(path,256));
                //fflush(stdout);

                printf_info();//封装 zyq@localhost:   -$

                char buff[128] = {0};
                fgets(buff,128,stdin); //"ls\n"
                buff[strlen(buff)-1] = 0;//去除\n
                
				char* argv[ARGC] = {0};
                char* cmd = get_cmd(buff,argv); //得到参数的数组

                if(cmd == NULL)
                {
                        continue;
                }

                else if(strcmp(cmd,"exit")==0)
                {
                        break;
                }
                else if(strcmp(cmd,"cd")==0)
                {
                        if(argv[1]!=NULL)
                        {
                                if(chdir(argv[1])!=0)
                                {
                                        perror("cd error");
                                }
                        }
                        continue;
                }
                
				pid_t pid = fork();
                if(pid == -1)
                {
                        continue;
                }
                if(pid == 0)
                {
                        //execv  参数: 路径  名称(argv 参数)
                        //execvp(cmd,argv); //多个参数

                        char path[256] = {0};
                        if(strncmp(cmd,"./",2) == 0 || strncmp(cmd,"/",1) == 0)
                        {
                                strcpy(path,cmd);
                        }
                        else
                        {
                                strcpy(path,PATH);//把我们提前写好程序的目录拷贝如path
                                strcat(path,cmd);//在path后面添加上目录下的命令名字
                        }
                        execv(path,argv);
                        printf("exec error");
                        exit(0);
                }

                wait(NULL);
        }
}

个人实现的一些mybin代码

clear

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>

int main()
{
	printf("\033{2J\033{0:0H");
}

ls

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<dirent.h>
#include<sys/types.h>
#include<sys/stat.h>


//opendir 打开目录流
//readdir
//closedir

int main()
{
	char path[256] = {0};
	getcwd(path,256);//获取当前位置

	//打开目录流
	DIR * p = opendir(path);
	if(p == NULL)
	{
		return 0;
	}
	//读目录流
	struct dirent * s = NULL;
	while((s = readdir(p)) != NULL )
	{
		if(strncmp(s->d_name,".",1) == 0)
		{
			continue;
		}
		struct stat st;
		stat(s->d_name,&st);

		if(S_ISDIR(st.st_mode))//判断是不是目录
		{
			printf("\033[1;34m%s  \033[0m",s->d_name);
		}
		else
		{
			if(st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
			{
				printf("\033[1;32m%s  \033[0m",s->d_name);
			}
			else
			{
				printf("%s  ",s->d_name);
			}
		}

	}
	//关闭目录流
	printf("\n");
	closedir(p);
}

这里使用的了DIR函数,来实现ls的一系列操作,并且对颜色进行了调整,更加真实且实用。

pwd

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>

int main()
{
	char path[256] = {0};
	getcwd(path,256);
	printf("%s\n",path);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值