Linux C语言实现自己的shell命令

引言

在暑假留校的第二周,我们的项目是学习进程并切实现自己的shell;关于什么是shell请大家自行百度,简单来说shell就是指一个面向用户的命令接口,表现形式就是一个可以由用户录入的界面,这个界面也可以反馈运行信息;

不是目录的目录

  1. 项目需求
  2. 如何实现
  3. 源代码

1.项目需求

在这里插入图片描述
关于进阶需求我们只讲述管道的实现,对与后面三个,全部都是调用readline这个库我们不做概述

2.1有一个好看的shell界面

//打印提示符
void print_prompt()
{
	struct passwd *usrname;
	usrname = getpwuid(getuid());
	char buf[256];
	memset(buf,0,sizeof(buf));
	printf("my_shell:%s",getcwd(buf,256));
	if(strcmp(usrname->pw_name,"root")==0)
		printf("#");
	else
		printf("$");
}

我们为了和终端真实的界面差不多,所以在这里花费了一些心思;
首先是通过getcwd()获得了当前所在目录;
然后通过getpwuid(getuid())获得了当前的实际用户是root还是一般用户;

2.2内建命令cd的实现

这是我实现的第一个需求,因为内建命令不需要开进程,所以我选择先实现cd命令,实现了进阶功能cd -;
关于cd -的实现本来我想使用队列来解决,但是其实只有两个数据,所以我采用了if - else来进行简单实现;

struct dd{
	char haha[2][256];
	int ha;
}cd;

//内置命令直接执行
void in_cd(char list[100][256],int cont)
{
	if(strcmp(list[0],"cd") != 0)
		return;
	char buf[256];
	struct passwd *usrname;
	usrname = getpwuid(getuid());
	getcwd(cd.haha[cd.ha],sizeof(cd.haha[cd.ha]));
	if(cd.ha == 0)
		cd.ha++;
	else
		cd.ha--;
	if(strcmp(list[1],"~")==0)
	{
		if(strcmp(usrname->pw_name,"xzwb")==0)
			strcpy(buf,"/home/xzwb/");
		else if(strcmp(usrname->pw_name,"root")==0)
			strcpy(buf,"/root/");	
	}
	else if(strcmp(list[1],"-")==0)
		strcpy(buf,cd.haha[cd.ha]);
	else
		strcpy(buf,list[1]);
	chdir(buf);
}

上面就是cd命令的实现;

2.3重定向和管道和后台运行部分的实现

  1. 关于重定向的实现相对来说也挺简单的,就是判断你是不是重定向然后找到你重定向的文件,通过dup2()这个函数可以将重定向文件的文件描述符修改为0,1来实现输入输出重定向;
  2. 关于管道的实现就是先开一个进程执行管道的前一部分,存入文件中,然后再开一个进程执行后一部分将前一部分文件中的东西,使用dup2修改为标准输入;
  3. 后台运行命令是我觉得最简单的一部分,就是主进程要不要阻塞住等待子进程执行完毕;
//实现除了cd以外的外部命令
void in_command(char list[100][256] , int cont)
{
	int background = 0; //标识是否有后台运行符&
	int how = 0; //用于标识是否有><|
	pid_t pid;
	int i;
	int fd;
	int he;
	int statu;
	char *arg[256];
	char *arg2[256];
	char *file;
	for(i=0;i<cont;i++)
		arg[i] = (char*)list[i];
	arg[cont] = NULL;
	for(i=0;i<cont;i++)
	{
		if(strcmp(arg[i],">")==0)
		{
			file = arg[i+1];
			how += 1;
			he = i;
		}
		if(strcmp(arg[i],"<")==0)
		{
			file = arg[i+1];
			how += 2;
			he = i;
		}
		if(strcmp(arg[i],">>")==0)
		{
			file = arg[i+1];
			how += 11;
			he = i;
		}
		if(strcmp(arg[i],"<<")==0)
		{
			file = arg[i+1];
			how += 22;
			he = i;
		}
		if(strcmp(arg[i],"|")==0)
		{
			int c = 0;
			for(int j = i+1 ; j < cont;j++,c++)
				arg2[c] = arg[j];
			arg2[c] = NULL;
			how += 4;
			he = i;
		}
		if(strcmp(arg[i],"&")==0)
		{
			arg[i] = NULL;
			background += 1;
		}
	}
	if(how!=0)
		arg[he] = NULL;
	if(background == 1 && strcmp(list[cont-1],"&") != 0)
		background--;
	if((pid = fork())<0)
		perror("fork error\n");
	if(pid == 0)
	{
		switch(how)
		{
			case 0:
				{
					execvp(arg[0],arg);
					exit(0);
					break;
				}
			case 1:
				{
					fd = open(file,O_RDWR|O_CREAT|O_TRUNC,S_IRWXU);
					dup2(fd,1);
					execvp(arg[0],arg);
					exit(0);
					break;
				}
			case 2:
				{
					if((fd = open(file,O_RDONLY,0644)) < 0)
						printf("openfile falsh\n");
					close(0);
					dup2(fd,0);
					execvp(arg[0],arg);
					exit(0);
					break;
				}
			case 11:
				{
					fd = open(file,O_RDWR|O_CREAT|O_APPEND,S_IRWXU);
					dup2(fd,1);
					execvp(arg[0],arg);
					exit(0);
					break;
				}
			case 22:
				{
					if((fd = open(file,O_RDONLY)) < 0)
						perror("open");
					dup2(fd,0);
					execvp(arg[0],arg);
					exit(0);
					break;
				}
			case 4:
				{
					int pid2;
					int satu;
					int fd2;
					if((pid2 = fork()) < 0)
						perror("fork error");
					if(pid2 == 0)
					{
						if((fd2 = open("/tmp/1.txt",O_WRONLY|O_CREAT|O_TRUNC,0644)) < 0)
							perror("open");
						dup2(fd2,1);
						execvp(arg[0],arg);
						exit(0);
					}
					waitpid(pid2,&satu,0);
					close(fd2);
					fd2 = open("/tmp/1.txt",O_RDONLY);
					dup2(fd2,0);
					execvp(arg2[0],arg2);
					if(remove("/tmp/1.txt") < 0)
						perror("remove error");
					exit(0);
					break;
				}
			default:printf("输入错误!\n");
		}
	}
	if(background == 1)
		return;
	if(background == 0)
		waitpid(pid,&statu,0);
}

static void mask_ctrl_c(int signo)
{
	printf("\n");
	print_prompt();
	fflush(stdout);
}                         

3.源代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/stat.h>
#include <pwd.h>
#include <signal.h>
#include <readline/readline.h>
#include <readline/history.h>

struct dd{
	char haha[2][256];
	int ha;
}cd;

struct history{
	char a[100];
	struct history *next;
};

//打印提示符
void print_prompt()
{
	struct passwd *usrname;
	usrname = getpwuid(getuid());
	char buf[256];
	memset(buf,0,sizeof(buf));
	printf("my_shell:%s",getcwd(buf,256));
	if(strcmp(usrname->pw_name,"root")==0)
		printf("#");
	else
		printf("$");
}

//获得命令行输入
void get_input(char *buf)
{
	int len = 0;
	char ch;
	ch = getchar();
	while(len < 256 && ch != '\n')
	{
		buf[len++] = ch;
		ch = getchar();
	}
	if(len == 256)
	{
		printf("command is too long\n");
		exit(1);
	}
	buf[len] = '\n';
	buf[++len] = '\0';
}

//解析命令行
void explain_input(char *buf , int *cont , char list[100][256]) 
{
	int i=0;
	*cont = 0;
	int j;
	while(1)
	{
		if(buf[i] == ' ')
		{
			i++;
			continue;
		}
		if(buf[i] == '\n')
			break;
		else
		{
			j = 0;
			while(buf[i] != ' ' && buf[i] != '\n')
			{
				list[*cont][j] = buf[i];
				j++;
				i++;
			}	
			list[*cont][j] = '\0';
			*cont += 1;
		}
	}
}

//内置命令直接执行
void in_cd(char list[100][256],int cont)
{
	if(strcmp(list[0],"cd") != 0)
		return;
	char buf[256];
	struct passwd *usrname;
	usrname = getpwuid(getuid());
	getcwd(cd.haha[cd.ha],sizeof(cd.haha[cd.ha]));
	if(cd.ha == 0)
		cd.ha++;
	else
		cd.ha--;
	if(strcmp(list[1],"~")==0)
	{
		if(strcmp(usrname->pw_name,"xzwb")==0)
			strcpy(buf,"/home/xzwb/");
		else if(strcmp(usrname->pw_name,"root")==0)
			strcpy(buf,"/root/");	
	}
	else if(strcmp(list[1],"-")==0)
		strcpy(buf,cd.haha[cd.ha]);
	else
		strcpy(buf,list[1]);
	chdir(buf);
}

//实现除了cd以外的外部命令
void in_command(char list[100][256] , int cont)
{
	int background = 0; //标识是否有后台运行符&
	int how = 0; //用于标识是否有><|
	pid_t pid;
	int i;
	int fd;
	int he;
	int statu;
	char *arg[256];
	char *arg2[256];
	char *file;
	for(i=0;i<cont;i++)
		arg[i] = (char*)list[i];
	arg[cont] = NULL;
	for(i=0;i<cont;i++)
	{
		if(strcmp(arg[i],">")==0)
		{
			file = arg[i+1];
			how += 1;
			he = i;
		}
		if(strcmp(arg[i],"<")==0)
		{
			file = arg[i+1];
			how += 2;
			he = i;
		}
		if(strcmp(arg[i],">>")==0)
		{
			file = arg[i+1];
			how += 11;
			he = i;
		}
		if(strcmp(arg[i],"<<")==0)
		{
			file = arg[i+1];
			how += 22;
			he = i;
		}
		if(strcmp(arg[i],"|")==0)
		{
			int c = 0;
			for(int j = i+1 ; j < cont;j++,c++)
				arg2[c] = arg[j];
			arg2[c] = NULL;
			how += 4;
			he = i;
		}
		if(strcmp(arg[i],"&")==0)
		{
			arg[i] = NULL;
			background += 1;
		}
	}
	if(how!=0)
		arg[he] = NULL;
	if(background == 1 && strcmp(list[cont-1],"&") != 0)
		background--;
	if((pid = fork())<0)
		perror("fork error\n");
	if(pid == 0)
	{
		switch(how)
		{
			case 0:
				{
					execvp(arg[0],arg);
					exit(0);
					break;
				}
			case 1:
				{
					fd = open(file,O_RDWR|O_CREAT|O_TRUNC,S_IRWXU);
					dup2(fd,1);
					execvp(arg[0],arg);
					exit(0);
					break;
				}
			case 2:
				{
					if((fd = open(file,O_RDONLY,0644)) < 0)
						printf("openfile falsh\n");
					close(0);
					dup2(fd,0);
					execvp(arg[0],arg);
					exit(0);
					break;
				}
			case 11:
				{
					fd = open(file,O_RDWR|O_CREAT|O_APPEND,S_IRWXU);
					dup2(fd,1);
					execvp(arg[0],arg);
					exit(0);
					break;
				}
			case 22:
				{
					if((fd = open(file,O_RDONLY)) < 0)
						perror("open");
					dup2(fd,0);
					execvp(arg[0],arg);
					exit(0);
					break;
				}
			case 4:
				{
					int pid2;
					int satu;
					int fd2;
					if((pid2 = fork()) < 0)
						perror("fork error");
					if(pid2 == 0)
					{
						if((fd2 = open("/tmp/1.txt",O_WRONLY|O_CREAT|O_TRUNC,0644)) < 0)
							perror("open");
						dup2(fd2,1);
						execvp(arg[0],arg);
						exit(0);
					}
					waitpid(pid2,&satu,0);
					close(fd2);
					fd2 = open("/tmp/1.txt",O_RDONLY);
					dup2(fd2,0);
					execvp(arg2[0],arg2);
					if(remove("/tmp/1.txt") < 0)
						perror("remove error");
					exit(0);
					break;
				}
			default:printf("输入错误!\n");
		}
	}
	if(background == 1)
		return;
	if(background == 0)
		waitpid(pid,&statu,0);
}

static void mask_ctrl_c(int signo)
{
	printf("\n");
	print_prompt();
	fflush(stdout);
}                         

void history_ai(char list[100][256])
{
	if(strcmp(list[0],"history")==0)
	{
		read_history(NULL);
	}
}

int main()
{
	cd.ha = 0;
	int cont;
	int len;
	char list[100][256];
	signal(SIGINT,mask_ctrl_c);
	while(1)
	{
		char *buf = (char*)malloc(sizeof(256));
		memset(list,0,sizeof(list));
		memset(buf,0,sizeof(buf));
		print_prompt();
		buf = readline("myshell&");
		add_history(buf);
		write_history(NULL);
		buf[strlen(buf)] = '\n';		
		if(strcmp(buf,"exit\n") == 0)
			exit(0);
		explain_input(buf,&cont,list);
		in_cd(list,cont);
		history_ai(list);
		in_command(list,cont);
		free(buf);
	}
}
发布了35 篇原创文章 · 获赞 82 · 访问量 7544

猜你喜欢

转载自blog.csdn.net/qq_44049351/article/details/99702807