Linux 编写简易shell,支持输入输出重定向

引用前面写过的代码:https://blog.csdn.net/ihaha233/article/details/79833397

将void do_execute(void)替换为新写的void do_shell()即可实现。下面先看代码:

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


char *argv[64];
int argc = 0;

void do_parse(char* buf)
{
	int i;
	int status = 0;

	for(argc=i=0;buf[i];i++)
	{
		if(!isspace(buf[i])&&status == 0)
		{
			argv[argc++] = buf+i;
			status = 1;
		}
		else if(isspace(buf[i]))
		{
			status = 0;
			buf[i] = 0;
		}
	}
	argv[argc] = NULL;

}


void do_shell()
{
	pid_t id = fork();
	if(id < 0)
	{
		perror("fork");
		return;
	}
	if(id > 0)
	{
		//father
		wait(NULL);
	}
	else
	{
		//child
		int i = 0;
		int flag = 0;
		for(;argv[i] != NULL;i++)
		{
			if(strcmp(argv[i],"<") == 0)
			{
				//输入重定向
				flag = 1;
				break;
			}
			if(strcmp(argv[i],">") == 0)
			{
				//输出重定向
				flag = 2;
				break;
			}
		}
		if(flag == 0)
		{
			execvp(argv[0],argv);
			perror("execvp");
			exit(EXIT_FAILURE);
		}
		if(flag == 1)
		{
			//实现输入重定向
			argv[i] = NULL;
			int oldfd = open(argv[i+1],O_RDONLY,0644);
			if(oldfd < 0)
			{
				perror("oldfd\n");
				exit(1);
			}
			close(0);
			int newfd = dup(oldfd);
			if(newfd < 0)
			{
				perror("newfd\n");
				exit(2);
			}
			int ret = execvp(argv[0],argv);
			if(ret = -1)
			{
				perror("execvp");
				exit (EXIT_FAILURE);
			}
			
		}
		if(flag == 2)
		{
			//实现输出重定向
			argv[i] = NULL;
			int oldfd = open(argv[i+1],O_WRONLY|O_CREAT,0644);
			if(oldfd < 0)
			{
				perror("oldfd\n");
				exit(3);
			}
			close(1);
			int newfd = dup(oldfd);
			if(newfd < 0)
			{
				perror("newfd\n");
				exit(4);
			}
			int ret = execvp(argv[0],argv);
			if(ret = -1)
			{
				perror("execvp");
				exit (EXIT_FAILURE);
			}
		}
	}
}


			

int main(void)
{
	char buf[1024] = {};
	while(1)
	{
		printf("[myshell #]$");
		scanf("%[^\n]%*c",buf);
		do_parse(buf);
		//do_execute();
		do_shell();
	}
	return 0;
}

代码运行结果如下:


着重介绍dup函数

int dup(int oldfd);

int dup2(int oldfd,int newfd)

函数参数:
oldfd:要被复制的文件描述符
newfd:在dup2函数中指定的新文件描述符
返回值:
调用成功返回新的文件描述符

调用失败返回 -1     

使用dup或者dup2函数实现文件共享,返回的新的文件描述符 newfd 和原来的文件描述符 oldfd 是对应同一个文件表项(struct file结构体),所以共享同一个当前文件偏移量。因此在利用 newfd 和 oldfd 向文件中写入数据的时候是不会出现数据覆盖的问题。

 dup函数会返回进程中未使用的数值最小的文件描述符,这点和open函数是一样的。dup2函数会先关闭指定的文件描述符,然后返回该文件描述符作为新的文件描述符。
    dup2函数相当于先后执行了close函数和fcntl函数进行文件描述符的复制。如下图所示
    dup2函数和先后调用close和fcntl函数是不一样的,具体在于dup2函数关闭文件描述符和进行文件描述符复制这两个操作是作为一个原子操作执行的,是不能被打断的。

猜你喜欢

转载自blog.csdn.net/ihaha233/article/details/80295475