【Linux】文件重定向与实现支持文件重定向的minishell


目录

0.前提

​编辑

1.重定向

1.1重定向的本质

1.2dup2

1.3模拟实现输出重定向 >

1.4模拟实现追加重定向 >>

1.5模拟实现输入重定向 <

2.让minishell支持重定向


0.前提

文件描述符的分配规则:

在文件描述符表里面,从小到大按照顺序寻找最小的且没有被占用的fd。

【Linux】文件重定向与实现支持文件重定向的minishell_第1张图片


1.重定向

1.1重定向的本质

上层使用的fd不变,在内核中更改fd对应的struct file*的地址。

1.2dup2

【Linux】文件重定向与实现支持文件重定向的minishell_第2张图片

让newfd变成oldfd的拷贝,如果需要关闭newfd.

1.3模拟实现输出重定向 >

【Linux】文件重定向与实现支持文件重定向的minishell_第3张图片

1.4模拟实现追加重定向 >>

【Linux】文件重定向与实现支持文件重定向的minishell_第4张图片

1.5模拟实现输入重定向 <

【Linux】文件重定向与实现支持文件重定向的minishell_第5张图片

2.让minishell支持重定向

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

#define B_NUM 1024
#define ARGV_NUM 10
#define NONE_REDIR 0
#define INPUT_REDIR 1
#define OUTPUT_REDIR 2
#define APPEND_REDIR 3



char buffer[B_NUM];
char* myargv[ARGV_NUM];
int quitcode=0;
int quitsignal=0;

int redirType=NONE_REDIR;
char* refilename=NULL;


void Commandcheck(char* command)
{
  assert(command);
  //判断是否有重定向,有是哪种
  char* begin=command;
  char* end=command+sizeof command-1;
  
  while(begin')
    {
      *begin='\0';
      begin++;
      if(*begin=='>')
      {
         redirType=APPEND_REDIR;
         begin+=2;
         refilename=begin;
      }
      else{
        redirType=OUTPUT_REDIR;
        refilename=(++begin);
        break;
      }
    }
    if(*begin=='<')
    {
      *begin='\0';
       redirType=INPUT_REDIR;
       begin+=2;
       refilename=begin;
       break;
    }
    begin++;
  }
  return ;
}

int main()
{

  while(1)
  {
    redirType=NONE_REDIR;
    refilename=NULL;
    errno=0;
   
    printf("【用户名@服务器 当前目录】$");
    fflush(stdout);

    char* s=fgets(buffer,sizeof (buffer)-1,stdin);
    assert(s!=NULL);
    buffer[strlen (buffer)-1]=0;
    (void)s;
   
    //和重定向区分开
    Commandcheck(buffer);
    
   // printf("切割成功:命令 %s 文件 %s\n",buffer,refilename);


    //切割字符串
    myargv[0]=strtok(buffer," ");
    int i=0;

    if(myargv[0] != NULL && strcmp(myargv[0], "ls") == 0)
    {
      myargv[++i] = (char*)"--color=auto";
    }

    while(myargv[i]!=NULL)
    {
      myargv[++i]=strtok(NULL," ");
    }

    //实现cd功能
    if(myargv[0] != NULL &&strcmp(myargv[0],"cd")==0)
    {
      if(myargv[1]!=NULL)
      {

        chdir(myargv[1]);
      }
      continue;
    }
    //实现echo $?功能
    if(myargv[0]!=NULL&&myargv[1]!=NULL&&strcmp(myargv[0],"echo")==0)
    {
      if(strcmp(myargv[1],"$?")==0)
      {
        //输出上一个进程的退出码
        printf("退出码为:%d\n",quitcode);

      }
      else
      {
        printf("%s\n",myargv[1]);
      }
      continue;

    }

    pid_t id =fork();
    assert(id!=-1);
    if(id==0)
    {
      //子进程

      //如果有文件打开文件
      switch(redirType)
      {
        case NONE_REDIR:
          break;
        case INPUT_REDIR:
          {
          int fd=open(refilename,O_RDONLY);
            if(fd < 0){           
               perror("open");
               exit(errno);
            }
          dup2(fd,0);
          }
          break;
        case OUTPUT_REDIR:
        case APPEND_REDIR:
          {
            
          int flag=O_WRONLY|O_CREAT;
          if(redirType==OUTPUT_REDIR)
          {
            flag|=O_TRUNC;
          }
          else{
            flag|=O_APPEND;
          }
          umask(0);
          int fd=open(refilename,flag,0666);
            if(fd < 0){            
               perror("open");
               exit(errno);
            }
          dup2(fd,1);
          }
          break;
       default:
          break;

      }


      //程序替换
      execvp(myargv[0],myargv); 
      //如果走到这里表示替换失败
      exit(1);
    }

   //父进程
   int status=0;
   pid_t ret= waitpid(id,&status,0);
   assert(ret > 0);
   (void)ret;
   quitcode=(status>>8)&0XFF;
   quitsignal= (status & 0x7F);

  }
  return 0;
}

注意:每次父进程循环都要记得刷新 redirType 、redirFile、errno 


最后

加油

【Linux】文件重定向与实现支持文件重定向的minishell_第6张图片

你可能感兴趣的:(Linux的蜕变之路,linux,shell,dup2,重定向,学习)