用自己编写的简易shell实现文件重定向

先看下代码

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<ctype.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<assert.h>
#include<string.h>
#define NUM 1024
#define OPT_NUM 64
#define trimspace(start) do{\
    while(isspace(*start))\
      start++;\
}while(0)
#define NONE_REDIR 0
#define INPUT_REDIR 1
#define OUTPUT_REDIR 2
#define APPEND_REDIR 3
char  linecommand[NUM];
char *myargv[OPT_NUM];//指针数组
int redirnum=0;
char*redirname=NULL;
void commandcheck(char *commands)
{
  assert(commands);
  char*start=commands;
  char*end=commands+strlen(commands);
  while(start<end)
  {
    if(*start=='>')
    {
      *start='\0';
      start++;
      if((*start)=='>')
      {
        redirnum=APPEND_REDIR;
        start++;
        trimspace(start);
        redirname=start;
      }
      else
      {
        redirnum=OUTPUT_REDIR;
        trimspace(start);
        redirname=start;
      }
      break;

    }
    else if(*start=='<')
    {
      *start='\0';
      start++;
      trimspace(start);
      redirname=start;
      redirnum=INPUT_REDIR;
      break;
    }
    else 
    {
      start++;
    }
    
  }
}
int main()
{
  int  lastcod;
  int lastsig;
  while(1)
  {
    errno=0;
  redirnum=0;
  redirname=NULL;
  errno=0;
  printf("用户名@主机名 当前路径# ");
  fflush(stdout);
  char* s=fgets(linecommand,sizeof(linecommand)-1,stdin);
  assert(s!=NULL);
  linecommand[strlen(linecommand)-1]=0;
  (void)s;
  commandcheck(linecommand);
  myargv[0]=strtok(linecommand," ");
  int i=1;
  if(myargv[0]!=NULL&&strcmp(myargv[0],"ls")==0)
  {
    myargv[i++]=(char*)"--color=auto";
  }
 while(myargv[i++]=strtok(NULL," "))   
  if(myargv[0]!=NULL&&strcmp(myargv[0],"cd")==0)
  {
   if(myargv[1]!=NULL)
     chdir(myargv[1]);
   continue;
  }
  if(myargv[0]!=NULL&&myargv[1]!=NULL&&strcmp(myargv[0],"echo")==0)
  {
    if(strcmp(myargv[1],"$?")==0)
    {
      printf("%d %d\n",lastcod,lastsig);
    }
    else
    {
      printf("%s\n",myargv[1]);
    }
    continue;
  }
#ifdef DEBUG 
  for(int i=0;myargv[i];i++)
  {
    printf("myargv[%d]:%s\n",i,myargv[i]);
  }
#endif
  pid_t id=fork();
  assert(id!=-1);
  if(id==0)
  {
  switch(redirnum)
  {
    case NONE_REDIR:
      break;
    case INPUT_REDIR:
      {
        int fd=open(redirname,O_RDONLY);
        if(fd<0)
        {
          perror("open");
          exit(errno);
        }
        dup2(fd,0);
      }
      break;
    case OUTPUT_REDIR:
    case APPEND_REDIR:
      {
        umask(0);
        int flags=O_WRONLY|O_CREAT;
        if(redirnum==APPEND_REDIR)
          flags |=O_APPEND;
        int fd=open(redirname,flags,0666);
      
        if(fd<0)
        {
          perror("open");
          exit(errno);
        }
        dup2(fd,1);
        
      }
      break;
default:
      printf("bug?\n");
      break;
  }
  execvp(myargv[0],myargv);
  exit(-1);
  }
  int status=0;
  waitpid(id,&status,0);
  assert(id>0);
  (void)id;
  lastcod=((status>>8)&0xFF);
  lastsig=((status)&0x7F);
  }
  return 0;
}

命令是要给子进程来执行的,真正重定向的工作也要子进程完成。

如何重定向需要父进程给子进程传递信息。包括redienum,redirname。

重定向由子进程执行,这里的重定向不影响父进程。因为进程的独立性。

子进程是以父进程进行拷贝产生的,所以子进程的文件描述符表也是父进程复制的,它俩不是共用一个文件描述符表。而且如果共用一张表,子进程对文件描述符标的改动,父进程的文件描述符表会进行同样的改动,显然不符合进程的独立性。

但是父子进程文件描述符表存的地址是同一个文件的,父子进程是由进程管理的,文件不受进程的控制,文件不会因为拷贝子进程而进行拷贝。

子进程对文件进行操作,不会影响父进程对文件的操作,因为文件中存在引用计数。

close一个文件其实就是让引用计数-1。

要判断一个对象或结构体属于哪个进程或文件,就把它去掉,看它对那部分影响最大,就是那部分的。

执行程序替换的时候,曾经进程打开的重定向文件不会受到影响。

进程和被打开的文件和PCB等属于内核数据结构,程序替换时,进程的代码和数据与内存进行替换并不影响内核数据结构。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南种北李

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值