⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shell.cpp

📁 Linux shell实现,包括管道
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************/
/*作者:王伟*/
/*班级:自42*/
/*学号:2004011443*/
/*程序功能:模拟linux下shell环境,实现shell功能*/
/*日期:2007.6.1*/
/*****************************************************************************/

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h> 
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

#define BUFFERSIZE 80
int main(void) 
{
	char *read_order(char *buffer);		//从键盘中读取命令
	char **order_name(const char *input);	//返回每条命令
	int pipel(char * input);
	int pipe_number(const char *input);//统计管道数量
	int redirect(char *input);//输入输出重定向
	int order_number(const char *input);	//统计命令数量,以;相隔

	char *path,*buffer;
	char *all_order,**every_order;
	int i,pipe,k,number;

	if((buffer=(char *)malloc(BUFFERSIZE*(sizeof(char))))==0)
	{
		printf("error! can't malloc enough space for buffer\n");
		return (0);
	}

	while(1)
	{
		path=getcwd(NULL,0);	//取得当前所在路径
		printf("%s > $", path);
		all_order=read_order(buffer);		//读取命令
		if(all_order==NULL)
			continue;
		number=order_number(all_order);
		if (number<0)
			continue;
		every_order=order_name(all_order);
		i=0;
		while (i<number)
		{
			if(strlen(every_order[i])!=0)
			{
				k=pipe_number(every_order[i]);	//是否有管道
				if(k!=0)
					pipel(every_order[i]);
				else
					redirect(every_order[i]);	//输入输出重定向或普通命令
				//for debug
				//printf("%s\n",every_order[i]);
			}
			i++;
		}
		//释放申请的空间
		for(i=0;i<number;i++)
			free(every_order[i]);
		free(every_order);
		free(all_order);
		free(path);
	}
}
char **order_name(const char *input)	//返回每条命令
{
	int order_number(const char *input);	//统计命令数量,以;相隔

	int i,j,k,max_len;
	char **order;
	
	max_len=strlen(input);
	k=order_number(input);
	order=(char **)malloc(k*sizeof(char *));
	for(i=0;i<k;i++)
	{
		order[i]=(char *)malloc((max_len+1)*sizeof(char));
		order[i][0]='\0';
	}
	//分别取出被";"分割开的命令
	k=0;
	j=0;
	for (i=0;i<=max_len;i++)
	{
		if (input[i]!=';')
		{
			order[k][j]=input[i];
			j++;
		}
		else
		{
			order[k][j]='\0';
			k++;
			j=0;
		}
	}
	//show the orders that are departed by ';'
	/*for(i=0;i<k+1;i++)
		printf("%s\n",order[i]);*/
	return order;
}
int order_number(const char *input)	//统计命令数量,以;相隔
{
	int sum=0,i=0,len;
	len=strlen(input);
	while(i<len&&(input[i]==' '||input[i]=='	'))
		i++;
	if(input[i]==';')	//发生错误,出现;;
	{
		fprintf(stderr," syntax error near unexpected token: ;\n");
		return -1;
	}
	if (i==len)		//命令参数中只有空格或tab
		return -1;
	for (i=0;i<len;i++)
	if(input[i]==';')
	{
		while(i<strlen(input)&&(input[i+1]==' '||input[i+1]=='	'))
			i++;
		if(input[i+1]==';')	//发生错误,出现;;
		{
			fprintf(stderr," syntax error near unexpected token: ;;\n");
			return -1;
		}
		else
			sum++;
	}
	sum=sum+1;
	return sum;
}
int pipel(char * input)
{
	int redirect(char *input);
	int is_back(char *order);	//分析是否为后台进程,并且将字符&去掉
	int pipe_number(const char *input);	//统计管道数量	
		
	int status,i,j,k,**fd,back=0,len;
	char **order;
	int *child;
	
	back=is_back(input);
	len=strlen(input);
	k=pipe_number(input);
	order=(char **)malloc((k+1)*sizeof(char *));
	for(i=0;i<k+1;i++)
		order[i]=(char *)malloc((len+1)*sizeof(char));

	child=(int *)malloc((k+1)*sizeof(char *));
	fd=(int **)malloc(k*sizeof(int *));
	for(i=0;i<k;i++)
		fd[i]=(int *)malloc(2*sizeof(int));
	
	//分别取出被管道分割开的命令
	k=0;
	j=0;
	for (i=0;i<=len;i++)
	{
		if (input[i]!='|')
		{
			order[k][j]=input[i];
			j++;
		}
		else
		{
			order[k][j]='\0';
			k++;
			j=0;
		}
	}
	//test
	/*for(i=0;i<k+1;i++)
		printf("%s\n",order[i]);*/
	/*分析完毕*/

	//create the pipe
	for(i=0;i<k;i++)
		if(pipe(fd[i]) == -1) 
		{
			fprintf(stderr, "Open pipe error !\n");
			//printf("Open pipe error !\n");
			return 0;
		}
	//create the first child
	i=0;
	if((child[i]=fork())==0)
	{
		close(fd[i][0]);
		if(fd[i][1] != STDOUT_FILENO) 
		{
			// 将标准的输出重定向到管道的写入端,这样该子进程的输出就写入了管道
			if(dup2(fd[i][1], STDOUT_FILENO) == -1) 
			{
				fprintf(stderr, "Redirect Standard Out error !\n");
				//printf("Redirect Standard Out error !\n");
				return -1;
			}
			//关闭写入端
			close(fd[i][1]);
		}
		redirect(order[i]);	
		exit(1);	//child1 exit
	}
	else
	{
		//wait for child
		waitpid(child[i],&status,0);
		close(fd[i][1]);
	}
	i++;
	while(i<k)
	{
		if ((child[i]=fork())==0)
		{
			if(fd[i][0] != STDIN_FILENO) 
			{
				// 将标准的输入重定向到管道的读入端
				if(dup2(fd[i-1][0], STDIN_FILENO) == -1) 				
				{
					fprintf(stderr, "Redirect Standard In error !\n");
					//printf("Redirect Standard In Error !\n");
					return -1;
				}
				close(fd[i-1][0]);
				// 将标准的输出重定向到管道的写入端,这样该子进程的输出就写入了管道
				if(dup2(fd[i][1], STDOUT_FILENO) == -1) 				
				{
					fprintf(stderr, "Redirect Standard Out error !\n");
					//printf("Redirect Standard Out error !\n");
					return -1;
				}
				close(fd[i][1]);
			}
			redirect(order[i]);
			exit(1);
		}
		else
		{
			//wait for child
			waitpid(child[i],&status,0);
			close(fd[i][1]);
			i++;
		}
	}
	//create the last child
	if((child[i] = fork()) == 0) 
	{
		close(fd[i-1][1]);
		if(fd[i-1][0] != STDIN_FILENO) 
		{
			// 将标准的输入重定向到管道的读入端
			if(dup2(fd[i-1][0], STDIN_FILENO) == -1) 
			{
				fprintf(stderr, "Redirect Standard In error !\n");
				//printf("Redirect Standard In Error !\n");
				return -1;
			}
			close(fd[i-1][0]);
		}
		redirect(order[i]);
		exit(1);
	}
	else if(back==0)  
	{
		waitpid(child[i], NULL, 0);
		close(fd[i-1][1]);
	}
	//释放申请的空间
	for(i=0;i<k;i++)
		free(fd[i]);
	free(fd);
	for(i=0;i<k+1;i++)
		free(order[i]);
	free(order);
	free(child);
	return 1;
	/**************************************************/
}

int pipe_number(const char *input)//统计管道数量
{
	int sum=0,i;
	for (i=0;i<strlen(input);i++)
	if(input[i]=='|')
		sum++;
	return sum;
}
void do_cd(char *argv[])	//专门用于cd命令
{ 
	if(argv[1]!=NULL)
	{ 
		if(chdir(argv[1])<0) 
			switch(errno)
		{ 
			case ENOENT: 
				fprintf(stderr,"DIRECTORY NOT FOUND\n"); 
				break; 
			case ENOTDIR: 
				fprintf(stderr,"NOT A DIRECTORY NAME\n"); 
				break; 
			case EACCES: 
				fprintf(stderr,"YOU DO NOT HAVE RIGHT TO ACCESS\n"); 
				break; 
			default: 
				fprintf(stderr,"SOME ERROR HAPPENED IN CHDIR\n"); 
		} 
	}
} 
int redirect(char *input)	//重定向处理
{
	char **analize(const char *input);	//分析键入的命令,获取命令和参数并保存在arg中
	char *is_file_exist(const char *order);		//判断命令是否存在
	void do_cd(char *argv[]);	//专门用于cd命令

	int number(const char *input);	//分析命令和参数数量,来划分相应字符串
	int is_back(char *order);	//分析是否为后台进程,并且将字符&去掉
	int pipe_number(const char *input);	//统计管道数量

	char *order_path,*real_order;
	char *out_filename,*in_filename;
	char **analized_order;
	int len,status,i,j,k,back=0,fd_out,fd_in,flag_out=0,flag_in=0;
	pid_t pid;
	
	back=is_back(input);
	len=strlen(input);
	out_filename=(char *)malloc((len+1)*(sizeof(char)));
	in_filename=(char *)malloc((len+1)*(sizeof(char)));
	real_order=(char *)malloc((len+1)*(sizeof(char)));

	//读取字符串中的命令,并存放于real_order中
	for(i=0;i<len;i++)
	{
		if (input[i]!='>'&&input[i]!='<')
			real_order[i]=input[i];
		else
		{
			if (input[i]=='>')
				flag_out=1;
			if (input[i]=='<')
				flag_in=1;
			break;
		}
	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -