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

来源:互联网 发布:在联通云数据工作好吗 编辑:程序博客网 时间:2024/06/13 22:25

问题描述:

使用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 <stdio.h>#include <stdlib.h>#include <ctype.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <sys/types.h>#include <sys/wait.h>#include <dirent.h>#include <stdbool.h>char buf[150];    // save the input commandchar command[20][30];  //save the commands that is splitedint commandNum = 0;    // save the numbers of commandchar inputFilename[30];   //save the input file name if it existsbool isInputExist = 0;    //save the state of existence of input filechar outputFilename[30];   //save the output file name if it existsbool isOutputExist = 0;    //save the state of existence of output filechar *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,2char *str = buf;char ch;int flag = 0;while(ch=*str++){if(ch == '|')  //start to save another command{state = 0;     //command statei++;j=0;continue;}else if(ch == '<')  //start to save the input file name{state = 1;         //input file name stateisInputExist = 1;continue;}else if(ch == '>'){state = 2;      //output file name stateisOutputExist = 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 commandsDealCommandStr();  //deal the input stringchar * 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


0 0
原创粉丝点击