自己的shell

      相信接触过linux过,听过的人都知道linux的源代码是公开的,那么我们是不是可以看看我们平时最常用的命令是怎么实现的吧!看其实没那重要,重要的是你要裂解,然后根据自己的理解自己实现,然后和源代码做对比,学习借鉴,取长补短,那应该是一种比较好的学习方式了吧!

     那我今天就来把我自己的想法写在这里!

在写命令之前,我们都知道,命令必须在命令解释器下,才能完美的运行起来,脱离这个平台,那么它不过就是一堆字母吧!

 第一步(很重要的一步):命令解释器的实现,简单来说呢,就是是怎么把命令调起来然后实现的,也许你一会第一反应exec,exec是完全替换自己的代码,把你要调的完全复制过来,成功可是不反悔,失败就返回。对他是我们命令解释器少不了的函数。

不妨将这个函数列举一下:

     1. execl(const char *pathnaem,const char *arg,....(char *)0); 以参数形式列出

举例:当前文件下的main 想调起来,使用execl("./main","./main",(char *)0);

     2. execv(const char *pathname,char *const argv[]); 

举例:当前文件下的main 想调起来,使用

        char *argv[] = {"./main","./main",NULL};

        execv("./main",argv);

    3.execve(const char * pathname,  char *const argv[],   char *const envp[]);

    4.execvp(const char *filename,char *const argv[]); 将系统的环境变量给保护起来。

简单就是这几个,还有很多,还待查。

剩下的就是简单的函数使用了。

看看代码,具体函数具体解释:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<string.h>
#include<signal.h>
#include<pwd.h>
#define MAXSIZE 10
#define MYPATH "/home/yu/Desktop/mbash/mybin/"
void printfl()
{
	int id = getuid();
	char *s = "$";
	if(id == 0)
	{
		s = "#";
	}
	struct passwd *p = getpwuid(id);
	char hostname[128] ={0};
	gethostname(hostname,128);
	char *m = strtok(hostname,".");
	char buff[256] = {0};
	char *ps = "/";
	getcwd(buff,128);
	char *ql = strtok(buff,"/");
	while(ql!= NULL)
	{
		ps = ql ;
		ql = strtok(NULL,"/");
	}
	printf("[**%s@ %s %s]%s ",p->pw_name,m,ps,s);
	fflush(stdout);
}
int main()
{
	while(1)
	{
		//printf("[yu@localhost %s]$ ");
		//fflush(stdout);
		printfl();
		char buff[128] = {0};
		fgets(buff,128,stdin);
		buff[strlen(buff)-1] = 0;
		char *myargv[MAXSIZE] = {0}; 
		int i = 1;
	    char*s = strtok(buff," ");
	    if(s == NULL)
	    {
		   continue;
	    }
	    myargv[0] = s;
		while((s = strtok(NULL," ")) != NULL)
		{
			myargv[i++] = s;
		}
		if(strcmp(myargv[0], "cd") == 0)
		{
            if(chdir(myargv[1]) == -1)
		    {
               printf("mybash is error!\n");
		    }
			continue;
		}
		if(strcmp(myargv[0],"exit") == 0)
		{
			exit(0);
		}
		pid_t pid = fork();
		if(pid == 0)
		{
		   //execlp(buff,buff,(char *)0);
		   //execvp(myargv[0],myargv);
		   char path[512] = {0};
		   if(strncmp(myargv[0],"/",1) != 0 && strncmp(myargv[0],"./",2)!=0)
		   { //以绝对路径或者相对路径执行可执行文件。
			   strcpy(path,MYPATH);
		   }
		   strcat(path,myargv[0]);
		   execv(path,myargv);
		   printf("mybashis error:\n");
		   exit(0);子进程结束,那也就是exec失败,那么就会退出子进程。
		}
		wait(NULL);
	}
	return 0;
}

1.getuid() 获取当前用户的uid   如果结果 == 0 那么是root,否则是普通用用户。

2.struct passwd *p = getpwuid(id); 根据当前用户的uid 获取当前用户的名字,名字存在p这个结构体中,pw_name 当前用户的名字。

3.gethostname(hostname,128); 获取当前主机名,

4.strtok(hostname,".");分割字符串,遇到.分割,分割后就将那个地方置换成\0,下次要想再次置换那就从NULL开始,,再次分割。

5.getcwd(buff,128); 获取当前的路径,根据路径可以将终端提示里面的[yu@local. 当前路径]。

     这就是简单的命令解释器的实现,那么我们具体可以根据这些函数,对这个命令解释器的实现有一个很好理解。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值