linux實現簡單的shell以及管道

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<unistd.h>
#include<sys/wait.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
using namespace std;

const int shellnum =32;
const char * file_all = {"shell-all.txt"};
const char * file_half = {"shell-half.txt"};
//把輸入轉換爲exec函數組可用的參數
void cmd2argv(char **, char *);
//沒有 | 的情況
void cmd_no_grep(char **, char *);
//需要管道的情況
void cmd_with_grep(char **, char *, int );
//用來完成管道
bool fileReverse();
//輸出到屏幕
void file2Srcn();
int main()
{
       char cmd_line[1024];
       char * arg[shellnum];
       char *cmd_grep = NULL;
        //int out_save = dup(STDOUT_FILENO); 
        //int in_save = dup(STDIN_FILENO);
       int time=0;
       memset(cmd_line, 0, sizeof(cmd_line));
       cout<<">>";
       while(fgets(cmd_line, sizeof(cmd_line), stdin))
       {
               /*
                        如果有管道的話,相當於是把A的結果作爲B的輸入
                        這裏的file_all就是用來存放A的結果
                        所以每次輸入命令,需要清空這個文件
               */
                int fd = open(file_all, O_TRUNC | O_CREAT, 0644);
                close(fd);
               cmd_line[strlen(cmd_line)-1] = '\0';
               //判斷是否有管道
               if(strchr(cmd_line, '|'))
               {
                        cmd_grep = strtok(cmd_line, "|");
                        //cout<<"cmd:"<<cmd_grep<<endl;
                       while(cmd_grep)
                       {
                               cmd_with_grep(arg, cmd_grep,time++);
                               cmd_grep = strtok(NULL, "|");
                       }
                int fd = open(file_all,  O_RDONLY, 0644);
                file2Srcn();
                close(fd);
               }
                else
                {
                        cmd_no_grep(arg, cmd_line);
                }
                cout<<"\n>>";
       }
}

void cmd2argv(char **argv, char *cmd)
{
        int cnt=0,bg=0,end=0;
        while(cmd[bg] != '\0')
        {
                //去除命令前面的空格
                while(cmd[bg] == ' ')
                        bg++;
                end = bg;
                //確定命令的結尾
               while(cmd[end] != ' ' && cmd[end] != '\0')
                        end++;
                /*
                        下面這個判斷時因爲下面這種情況我這段代碼會有bug
                        ls -l  (l後面還有兩個空格)
                        這是程序會成功拆開ls和-l 但是此時由於-l後面不是\0
                        所以while循環還會繼續,但是這種情況最後 bg == end
                        所以用下面這個判斷進行避免  
                */
                if(bg != end)
                {
                        argv[cnt] = new char[end-bg+1];
                        strncpy(argv[cnt],  cmd+bg, end-bg);
                        //cout<<":"<<argv[cnt]<<":"<<endl;
                        cnt++;
                        bg = end+1;
                        end++;
                }
                
        }
        argv[cnt] =NULL;
}

void cmd_no_grep(char ** arg, char *cmd_line)
{
        cmd2argv(arg, cmd_line);
        pid_t pid = fork();
        if(0 == pid)
        {
                execvp(arg[0], arg);
        }
        else
        {
                wait(NULL);
        }
}


void cmd_with_grep(char ** arg, char *cmd_line, int time)
{
        int fd = open(file_all,O_WRONLY | O_CREAT ,0644);
        int out_save = dup(STDOUT_FILENO); 
        int in_save = dup(STDIN_FILENO);
        /*
        A|B 對於A,它的輸入是標準輸入,輸出的話重定向到文件shell-half.txt
        */
        if(time == 0)
        {
               cmd2argv(arg, cmd_line);
               dup2(fd, STDOUT_FILENO);
               pid_t pid = fork();
               if(0 == pid)
                {
                        execvp(arg[0], arg);
                }
                else
                {
                        sleep(0.1);
                        wait(NULL);
                        close(fd);
                }
        }
        else
        {
                /*
                        A|B 對於B來說,輸入輸出都得重定向
                        輸入 file_all.txt
                        輸出 file_half.txt
                        所以我們再最下面調用fileReverse()函數把half.txt拷貝到all.txt
                        (這裏這麼做是因爲,我們在使用exec函數的時候要保證all.txt是我們想要的輸入)
                */
               int fd_in = open(file_all,O_RDWR  ,0644);
               int fd_half = open(file_half,O_RDWR | O_CREAT | O_TRUNC, 0644);
               cmd2argv(arg, cmd_line);
               dup2(fd_in, STDIN_FILENO);
               dup2(fd_half, STDOUT_FILENO);
               pid_t pid = fork();
               if(0 == pid)
                {
                        if(execvp(arg[0], arg) < 0)
                        {
                                perror("error:");
                        }
                        
                }
                else
                {
                        sleep(0.1);
                        wait(NULL);
                        close(fd_in);
                        close(fd_half);
                        bool res = fileReverse();
                }
                 
        }
        dup2(out_save, STDOUT_FILENO);
        dup2(in_save, STDIN_FILENO);
        close(fd);
}

bool fileReverse()
{
        int fd_read = open(file_half,O_RDONLY);
        if(-1 == fd_read)
        {
                perror("open");
                exit(1);
      }
      int fd_write = open(file_all,O_CREAT | O_WRONLY | O_TRUNC, 0664);
      if(-1 == fd_write)
      {
          perror("create");
          exit(1);
      }
        char *str = new char[1024];
        int count = read(fd_read, str, sizeof(str));
        if(-1 == count)
        {
                perror("read");
                return false;
        }
        while(count)
        {
        write(fd_write, str, count);
        count = read(fd_read, str, sizeof(str));
        }
        return true;
}

void file2Srcn()
{
        int fd_read = open(file_all,O_RDONLY);
	if(-1 == fd_read)
	{
		perror("open");
		exit(1);
	}
	char *str = new char[1024];
	int count = read(fd_read, str, sizeof(str));
	if(-1 == count)
	{
		perror("read");
		exit(1);
	}
	while(count)
	{
		write(STDOUT_FILENO, str, count);
		count = read(fd_read, str, sizeof(str));
	}
}

目前支持shell解析以及管道,但是重定向這種還沒實現

實現方法不是最優,很蠢,大家發現問題歡迎下方留言討論

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章