Linux下 Mini-shell的实现(C/C++)

问题描述:

使用C语言在Linux下实现一个mini-shell,该shell从是stdin里面读取命令,然后执行该命令。

输入:

输入包含单行多命令,命令之间使用管道符('|')连接,可以使用输入输出重定向功能,

输入的BNF规范 :

 
  
    line ::= command ("|" command)* [redirection]    
    redirection ::= [input_redirection] [output_redirection] | [output_redirection] [input_redirection]
    input_redirecton ::= "<" filename
    output_redirecton ::= ">" filename
    command ::= file_name argument*

输出:

程序本身不输出任何东西,它的exit code就是输入一行命令中最后一个子命令的exit code


源码:

//Written by Openking 2014-11-15
/*Usage: inputs a line of commands connected by '|'
For example: ls -l | less > test.txt
*/

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

char buf[150];    // save the input command
char command[20][30];  //save the commands that is splited
int commandNum = 0;    // save the numbers of command
char inputFilename[30];   //save the input file name if it exists
bool isInputExist = 0;    //save the state of existence of input file
char outputFilename[30];   //save the output file name if it exists
bool isOutputExist = 0;    //save the state of existence of output file
char *arg[20];


char * trim(char * src)
{
	int i = 0;
	char *begin = src;
	while(src[i] != '\0')
	{
	    if(src[i] != ' ')
	    {
	        break;
	    }
	    else
	    {
	        begin++;
	    }
	   	i++;
	}
	for(i = strlen(src)-1; i >= 0;  i--)
	{
	    if(src[i] != ' ')
	    {
	        break;
	    }
	    else
	    {
	        src[i] = '\0';
	    }
	}
	return begin;
}

int DealCommandStr()    //analysis the command
{
	int i=0,j=0;
	int p=0,q=0;
	int state = 0;  //state = 0,1,2
	char *str = buf;
	char ch;
	int flag = 0;

	while(ch=*str++)
	{
		if(ch == '|')  //start to save another command
		{
			state = 0;     //command state
			i++;
			j=0;
			continue;
		}
		else if(ch == '<')  //start to save the input file name
		{
			state = 1;         //input file name state
			isInputExist = 1;
			continue;
		}
		else if(ch == '>')
		{
			state = 2;      //output file name state
			isOutputExist = 1;
			continue;
		}
		else
		{
			if(state == 0)   //command state
			{
				command[i][j++] = ch;
			}
			else if(state == 1)  //input file name state
			{
				inputFilename[p++] = ch;
			}
			else    //output file name state
			{
				outputFilename[q++] = ch;
			}
		}
		commandNum = i;   //get the number of commands
	}
	//for(i = 0;i <= commandNum; i++)
	//{
	//	puts(command[i]);
	//}
}

int main()
{
	int i=0,j=0;
	gets(buf);     //get commands
	DealCommandStr();  //deal the input string
	char * str_temp;
	char * readStr;
	char * writeStr;
	pid_t pid[30];
	int pipefd1[2] = {-1,-1};
	int pipefd2[2] = {-1,-1};
	int fdr,fdw;
	int ii=0;
	    /* fork count child process */
	if(commandNum == 0)
	{
        //pid_t fork(void);
        pid[0] = fork();
		if(pid[0] == 0)
		{
			if(isInputExist)
            {
            	fdr = open(trim(inputFilename),O_RDONLY);
            	dup2(fdr, STDIN_FILENO);
            }
            if(isOutputExist)
            {
            	fdw = open(trim(outputFilename),O_WRONLY|O_CREAT|O_TRUNC,0600);
            	dup2(fdw, STDOUT_FILENO);
            }
            /* child process */
            //int execvp(const char *file, char *const argv[]);
            //PureCommandStr(command[0]);
            int iii=0;
            char *buffer = trim(command[0]);
            //puts(buffer);
            while((arg[iii++] = strsep(&buffer," "))!= NULL);
            //setbuf(stdout, NULL);
			//char *a = "ls";
			//char *b[]={"ls","-a"};
			//execvp(b[0],b);
			//printf("%s   %s\n",arg,argv2);
            execvp(arg[0], arg);
            exit(0);
        }
    }
    else
    {
		//printf("command num %d\n",commandNum);
	    for(i = 0; i <= commandNum+1; i++)
	    {
	    	//printf("i num: %d\n",i);
	        /* init pipe file descriptor */
	        pipe(pipefd1);

	        /* fork child i */
	        pid[i] = fork();
	        //printf("pid num: %d\n",pid[i]);

	    	if(pid[i] == 0)
	    	{
	            /* child i */

	            //int dup2(int oldfd, int newfd);
	            if(i == 0)
	            { /* the first child */
	            	close(pipefd1[0]);
	                if(isInputExist)
	                {
	                	fdr = open(trim(inputFilename),O_RDONLY);
	                	dup2(fdr, STDIN_FILENO);
	                }
	                dup2(pipefd1[1], STDOUT_FILENO);
	                close(pipefd1[1]);

	            }
	            else if(i == commandNum)
	            { /* the last child */
	            	dup2(pipefd2[0], STDIN_FILENO);
	                close(pipefd2[1]); /* close prev process end of write */
	                close(pipefd2[0]); /* close curr process end of read */

	                if(isOutputExist)
	                {
	                	fdw = open(trim(outputFilename),O_WRONLY|O_CREAT|O_TRUNC,0600);
	                	dup2(fdw, STDOUT_FILENO);
	                }
	            }
	            else
	            {
	            	dup2(pipefd1[1], STDOUT_FILENO);

	            	close(pipefd1[0]);
	                close(pipefd1[1]);

	                dup2(pipefd2[0], STDIN_FILENO);

	                close(pipefd2[0]);
	                close(pipefd2[1]);
	            }
	            //int execvp(const char *file, char *const argv[]);
	            //PureCommandStr(command[i]);
				//char *argv2 = command[i];
				int iii=0;
            	char *buffer = trim(command[i]);
            	//puts(buffer);
	            while((arg[iii++] = strsep(&buffer," "))!= NULL);
				//printf("%s   %s\n",arg,argv2);
				execvp(arg[0], arg);
				//printf("i num: %d\n",i);
	        }

	        if(i!=0)
		    {
		      	close(pipefd2[0]);
		      	close(pipefd2[1]);
		    }
			  	pipefd2[0]=pipefd1[0];
			  	pipefd2[1]=pipefd1[1];
		}
	}

    for(i = 0; i <=commandNum; i++)
    {
        //pid_t waitpid(pid_t pid, int *status, int options);
        waitpid(pid[i], NULL, 0);
    }
}

测试:我们使用命令:

ls -l | less > test.txt


在文件test.txt可以看到结果:

total 32
-rw------- 1 openking openking    33  1月 18 13:22 1.txt
-rw-rw-r-- 1 openking openking  8294 11月 21 16:42 shell.cc
-rwxrwxr-x 1 openking openking 13471  1月 18 13:21 shell.o
-rw------- 1 openking openking     0  1月 18 13:24 test.txt


你可能感兴趣的:(C/C++,Linux)