【lesson38】让minishell支持重定向

minishell支持重定向

支持重定向的核心逻辑:
1.分析字符串是否含有重定向的符号,并且提取文件名。

#define INPUT_REDIR 0  //输入重定向
#define OUTPUT_REDIR 1 //输出重定向  
#define APPEND_REDIR 2 //追加重定向  
#define NONE_REDIR 4   //没有重定向   
int redir_status = NONE_REDIR;//状态

char* CheckRedir(char* start)    
{    
  assert(start);    
  char* end = start + strlen(start)-1; 
  
  //end执行指令的最后一个内容   
  while(start < end)    
  {    
    if(*end == '>')    
    {    
      if(*(end -1) == '>')    
      {    
        //ls -a -l>>log.txt\0  追加
        redir_status = APPEND_REDIR;    
        *(end-1) = '\0';    
        end++;    
        break;    
      }                                                                                                                                                                 
    
      //ls -a -l>log.txt\0   输出
      redir_status = OUTPUT_REDIR;    
      *(end) = '\0';    
      end++;    
      break;
    }
    else if(*end == '<')
    {
      //ls -a -l<log.txt\0  输入
      redir_status = INPUT_REDIR;
      *end = '\0';
      end++;
      break;
    }
    else 
    {
      end--;
    }
  }

  //循环结束,如果end还是大于start,说明存在重定向
  if(end > start)
  {
    return end;
  }
  //走到这说明不存在重定向
  return NULL;
}

例子:
在这里插入图片描述
end开始向前找重定向符
在这里插入图片描述
然后end++
在这里插入图片描述
这样end指向的就是文件名,start执行的就是指令内容。
然后就开始在子进程进行重定向了。

//printf("parent process create subprocess success\n");    
      if(sep)                                                                                                                                                           
      {    
        int fd = -1;    
        switch(redir_status)    
        {    
           case INPUT_REDIR:    
             fd = open(sep,O_RDONLY);    
             dup2(fd,0);    
             break;    
           case OUTPUT_REDIR:    
             fd = open(sep,O_WRONLY | O_CREAT | O_TRUNC,0666);    
             dup2(fd,1);    
             break;    
           case APPEND_REDIR:    
             fd = open(sep,O_WRONLY | O_CREAT | O_APPEND,0666);    
             dup2(fd,1);    
             break;    
           default:    
             assert(NULL);    
             break;    
        }    
      }

minishell完整代码

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

#define NUM 1024
#define SIZE 32
#define SEP " "

#define INPUT_REDIR 0
#define OUTPUT_REDIR 1
#define APPEND_REDIR 2
#define NONE_REDIR 4
int redir_status = NONE_REDIR;

char cmd_line[NUM];//array for saving command line
char* g_argv[SIZE];//the array are used to store paresed commands
char g_myval[64];

char* CheckRedir(char* start)
{
  assert(start);
  char* end = start + strlen(start)-1;
  while(start < end)                                                                                                                                                    
  {
    if(*end == '>')
    {
      if(*(end -1) == '>')
      {
      	//ls -a -l>>log.txt\0
        redir_status = APPEND_REDIR;
        *(end-1) = '\0';
        end++;
        break;
      }

      //ls -a -l>log.txt\0                                                                                                                                              
      redir_status = OUTPUT_REDIR;
      *(end) = '\0';
      end++;
      break;
    }
    else if(*end == '<')
    {
      //ls -a -l<log.txt\0
      redir_status = INPUT_REDIR;
      *end = '\0';
      end++;
      break;
    }
    else 
    {
      end--;
    }
  }

  if(end > start)
  {
    return end;
  }

  return NULL;
}
int main()
{
  //1.命令行解释器,一定是一个常驻内存的进程,不退出
  while(1)                                                                                                                                                              
  {
    //2.显示提示行
    printf("[xiaolin@localhost myshell]#");
    fflush(stdout);
    memset(cmd_line,'\0',sizeof cmd_line);
    //3.获取用户输入的字符串
    if(fgets(cmd_line,sizeof cmd_line,stdin) == NULL)
    {
      //if cmd_line empty contiue get command
      continue;
    }
    cmd_line[strlen(cmd_line)-1] = '\0';

    char* sep = CheckRedir(cmd_line);
    //4.对字符串进行解析
    int index = 0;
    g_argv[index++] = strtok(cmd_line,SEP);//Firest parse cmd_line 
    while(1)//Second parse cmd_line don't pass cmdline;
    {
      g_argv[index] = strtok(NULL,SEP);
      if(g_argv[index] == NULL) break;
      index++;
    }
    
    if(strcmp(g_argv[0],"ls") == 0)
    {
      g_argv[index++] = (char*)"--color=auto";
      g_argv[index] = NULL;
      } 

    if(strcmp(g_argv[0],"ll") == 0)
    {                                                                                                                                                                   
      g_argv[0] = (char*)"ls";
      g_argv[1] = (char*)"-l";
      g_argv[2] = (char*)"--color=auto";
      g_argv[3] = NULL;
    }
    
    // processing of built-in commands
    if(strcmp(g_argv[0],"cd") == 0)
    {
      //chdir() changes the current working directory of the calling process to the directory specified in path.
      if(g_argv[1] != NULL) chdir(g_argv[1]);
      continue;
    }
    if(strcmp(g_argv[0],"export") == 0 && g_argv[1] != NULL)
    {
      //There is a very hidden issue here
      //Ptuenv passes an environment variable as a pointer to it 
      //And g_ Argv [1] will be cleared on the next command_line read
      //In this way, the environment variable pointer points to a place with empty data, and this pointer is also a null pointer
      
      
      //int res = putenv(g_argv[1]);
      //if(res == 0) printf("export success\n");
      //else printf("export fail\n");
      
      //solve the problem
      strcpy(g_myval,g_argv[1]);
      int res = putenv(g_myval);
      if(res == 0) printf("export success\n");
      else printf("expor fail\n");
      continue;
    }
    /*//test if the g_argv array id correct                                                                                                                             
    for(index = 0; g_argv[index]; index++)
    {
      printf("g_argv[%d]:%s\n",index,g_argv[index]);
    }*/

    //5.create subprocess execute command
    pid_t id = fork();
    if(id == 0)
    {
      //subprocess
      //printf("parent process create subprocess success\n");
      if(sep)
      {
        int fd = -1;
        switch(redir_status)
        {
           case INPUT_REDIR:
             fd = open(sep,O_RDONLY);
             dup2(fd,0);
             break;
           case OUTPUT_REDIR:
             fd = open(sep,O_WRONLY | O_CREAT | O_TRUNC,0666);
             dup2(fd,1);
             break;
           case APPEND_REDIR:
             fd = open(sep,O_WRONLY | O_CREAT | O_APPEND,0666);
             dup2(fd,1);
             break;
           default:
             assert(NULL);                                                                                                                                              
             break;
        }
      }

      printf("subprocess starts running\n");
      execvp(g_argv[0],g_argv);
      printf("subprocess replace fail\n");
      
    }
    else if(id > 0)
    {
      //parent process
      int status = 0;
      pid_t res = waitpid(-1,&status,0);//blocking waiting
      if(res == -1)
      {
        printf("parent process wait subprocess fail\n");
      }
      else if(res > 0)
      {
        printf("parent process wait subprocess success exit_code:%d\n",WEXITSTATUS(status));
      }
      else 
      {
        printf("unkown error\n");
      }
    }
    else
    {
      //fail
      printf("parent procrss create subprocess fail\n");
    }
  }
  return 0;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值