Linux--自主shell加強版(支持輸入輸出重定向)

前面我們寫了一個基礎版本的shell,但有些功能沒有實現。這次我們直接在上次的基礎上將代碼稍加修改,使其支持輸入輸出重定向。
過程還是一樣:

· 獲取命令行
· 解析命令行
· 創建子進程(fork)
· 替換子進程(execvp)
· 父進程等待子進程退出(wait)

只不過這次解析命令行時需要對輸入重定向 (<)和 輸出重定向 (>)做特殊處理。

輸入重定向:關閉標準輸入,打開某普通文件,使其文件描述符爲0.
輸出重定向:關閉標準輸出,打開某普通文件,使其文件描述符爲1.

需要藉助dup()函數來複制文件描述符,傳給它一箇舊的文件描述符,調用成功返回新的文件描述符,返回的新的文件描述符 newfd 和原來的文件描述符 oldfd 對應同一個文件表項(struct file結構體),所以共享同一個當前文件偏移量。
代碼如下:

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

char *my_arg[32];
//執行命令
void do_execute()
{
        pid_t id = fork();//創建子進程
        if(id < 0)
        {
            perror("fork");
            return;
        }
        else if(id == 0)//子進程做其他事
        {
            int i = 0;
            int flag = 0;
            //判斷命令是否含輸入輸出重定向
            for( ;my_arg[i] != NULL;i++)
            {
                //輸出重定向
                if(strcmp(my_arg[i],">") == 0)
                {
                    flag = 1;
                    break;
                }
                //輸入重定向
                if(strcmp(my_arg[i],"<") == 0)
                {
                    flag = 2;
                    break;
                }
            }
            //處理輸出重定向
            if(flag == 1)
            {
                my_arg[i] = NULL;
                int oldfd = open(my_arg[i+1],O_WRONLY|O_CREAT,0777);
                if(oldfd < 0)
                {
                    perror("open");
                    exit(1);
                }
                close(1);
                int newfd = dup(oldfd);
                if(newfd < 0)
                {
                    perror("dup");
                    exit(1);
                }           
            }
            //處理輸入重定向
            if(flag == 2)
            {
                my_arg[i] = NULL;
                int oldfd = open(my_arg[i+1],O_RDONLY,0644);
                if(oldfd < 0)
                {
                    perror("open");
                    exit(1);
                }
                close(0);
                int newfd = dup(oldfd);
                if(newfd < 0)
                {
                    perror("dup");
                    exit(1);
                }
            }
            execvp(my_arg[0],my_arg);       
        }

        else
        {   //父進程等子進程退出
             int status = 0;
             pid_t ret = waitpid(id,&status,0);
             if(ret>0)
             {
                    printf("sig: %d,exit code: %d\n",status&0x7F,(status>>8)&0xFF);
             } 
             else
             {
                    printf("waitpid running error\n");
             }
        }
}
//解析命令行
void do_parse(char* cmd)
{
         cmd[strlen(cmd)-1] = 0;

         char *p = cmd;
         int i = 1;
         my_arg[0] = cmd;
         while(*p)
         {
              if(isspace(*p))
              {
                   *p = 0;
                   p++;

                   my_arg[i++] = p;
              }
              else
              { 
                   p++;

              }
         }
         my_arg[i] = NULL;
}

int main()
{
   char cmd[128];

   while(1)
   {
        printf("[myshell#] ");
        fgets(cmd,sizeof(cmd),stdin);
        do_parse(cmd);
        do_execute();
   }
    return 0;
}

測試結果如下:
這裏寫圖片描述

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