【linux】进程替换的应用|shell解释器的实现

当我们学过了进程替换之后,本篇文章可以根据进程替换的知识带你自主实现一个shell命令行
实现步骤

1.显示命令行提示
2.读取输入指令以及对应选项
3.分割第二步的指令以及选项到命令行参数表中
4.处理内建命令
5.进程替换

1.显示命令行提示

在这里插入图片描述

我们通过观察bash的命令行提示发现他是由三部分组成的
1.用户名
2.主机名
3.当前路径
而这三部分的信息都对应保存在我们的环境变量中
我们可以通过env指令查到
在这里插入图片描述

这里要介绍一个getenv函数,他可以将对应的环境变量对应的字符串打印出来,返回对应字符串的起始地址
在这里插入图片描述

我们可以封装3个函数分别来获取对应用户名,主机名,路径,这三个环境变量的字符串

//获取用户名的函数

  char*getname(){char *name=getenv("USER");if(name==NULL)return NULL;return name;                                                                                                       }

name指针保存USER环境变量值对应字符串的首地址,如果为NULL ,就返回空(说明不存在这个环境变量)

//获取主机名的函数

   char*gethostname(){char*hostname=getenv("HOSTNAME");if(hostname==NULL)return NULL;return hostname;}

hostname指针保存HOSTNAME环境变量值对应字符串的首地址,如果为NULL ,就返回空(说明不存在这个环境变量)

//获取路径的函数

 char*getpwd(){char*pwd=getenv("PWD");if(pwd==NULL)return NULL;return pwd;}

pwd指针保存PWD环境变量值对应字符串的首地址,如果为NULL,就返回空(说明不存在这个环境变量)


在这里插入图片描述
我们根据bash命令行的提示用getcommandline()函数来进行打印我们自己的命令行提示

 void getcommandline(){printf("[%s@%s %s]$",getname(),gethostname(),getpwd());}

当前步骤代码展示

 1 #include<stdio.h>2 #include <stdlib.h>3 char*getname()4 {5 char *name=getenv("USER");6 if(name==NULL)return NULL;7 return name;8 }9 char*gethostname()10 {11 char*hostname=getenv("HOSTNAME");12 if(hostname==NULL)return NULL;13 return hostname;14 }15 char*getpwd()16 {17 char*pwd=getenv("PWD");18 if(pwd==NULL)return NULL;19 return pwd;20 }21 void getcommandline()                                                                                              22 {23  printf("[%s@%s %s]$",getname(),gethostname(),getpwd());24 }  25 int main()26 {         27   getcommandline();28 29 }

效果展示
在这里插入图片描述


2.读取输入指令以及对应选项

为了处理我们输入的指令,我们需要将输入的指令以及选项保存在一个字符串中,就类比为命令行参数表.
我们应该如何读取字符串呢??
试想一下我们可以用scanf读字符串吗?
答案是不能的,因为我们在输入指令以及选项时,会带空格分割开来,而scanf会将空格作为分隔符,不会读取进来。
所以我们要使用的是fgets
在这里插入图片描述

 #include <stdio.h>char *fgets(char *s, int size, FILE *stream);

我们定义一个全局的字符串数组来保存输入的指令以及选项的字符串

char arr[512];

因为我们要从屏幕上读指令以及选项,所以fgets第三个参数为stdin(标准输入流).
我们先将其读到arr中,读取512个字节,然后使用strlen找到结尾添加‘\0’;比方说一个字符串为char arr[]=“abcdefg”;strlen(arr)=8; 我们需要在下标为strlen(arr)-1的位置添加一个‘\0’;
我们将获取指令,选项字符串封装在函数里面getcommandstr()

 27 void getcommandstr()                                      28 {                                                         29 fgets(arr,sizeof(arr),stdin);                             30 arr[strlen(arr)-1]='\0';                                  31 32 } 

为了测试arr是否读到,我们遍历打印一下arr数组
在这里插入图片描述

为了区别系统的和我们自己实现的,我们将]后面的$换成¥

效果展示
在这里插入图片描述
当前步骤代码展示

  1 #include<stdio.h>2 #include <stdlib.h>3 #include<string.h>4 char arr[512];5 6 char*getname()7 {8 char *name=getenv("USER");9 if(name==NULL)return NULL;10 return name;11 }12 char*gethostname()13 {14 char*hostname=getenv("HOSTNAME");15 if(hostname==NULL)return NULL;16 return hostname;17 }18 char*getpwd()19 {20 char*pwd=getenv("PWD");21 if(pwd==NULL)return NULL;                                                                                          22 return pwd;23 }24 void getcommandline()25 {26  printf("[%s@%s %s]$",getname(),gethostname(),getpwd());27 }                                                                                                                  28 void getcommandstr()29 {30 fgets(arr,sizeof(arr),stdin);31 arr[strlen(arr)-1]='\0';32 33 }34 int main()35 {36   getcommandline();37   getcommandstr();38   printf("%s",arr);39 40 }

3.分割第二步的指令以及选项到命令行参数表中

我们定义一个指针数组存放对应指令或者选项字符串的首地址,使用全局变量
默认可以存放32个字符串(指令或选项)的地址

#define NUM 32
char* str[NUM];

我们分隔字符串用strtok函数,可以去看看我的这边文章
strtok
在这里插入图片描述

我们要分隔开arr数组,所以arr数组是第一个参数,而要用空格分开

#define SEP ' ' 

而第二个参数我们传SEP就好了
而返回的地址则是第一个空格之前的字符串指令
接着我们给第一个参数传NULL,至于为什么,也在那个文章中讲到了

37 void splidcomandstr()
38 {
39  
40 str[0]=strtok(arr,SEP);
41 int index=1;
42 while(str[index++]=strtok(NULL,SEP));
43 }

将分开的第一个指令字符串的起始地址放在arr[0]中,然后循环将每个分隔开的字符串指令放在str[index]中,然后让index++,当arr字符串分割完之后,strtok返回NULL,给str[index],然后返回NULL,循环结束

效果展示
在这里插入图片描述

当前步骤代码展示

    1 #include<stdio.h>2 #include <stdlib.h>3 #include<string.h>4 char arr[512];5 #define NUM 326 char* str[NUM];7 #define SEP " "8 9 char*getname()10 {11 char *name=getenv("USER");12 if(name==NULL)return NULL;13 return name;14 }15 char*gethostname()16 {17 char*hostname=getenv("HOSTNAME");18 if(hostname==NULL)return NULL;19 return hostname;20 }21 char*getpwd()                                                                                                    22 {23 char*pwd=getenv("PWD");24 if(pwd==NULL)return NULL;25 return pwd;26 }27 void getcommandline()28 {29  printf("[%s@%s %s]$",getname(),gethostname(),getpwd());30 }                                                                                                                31 void getcommandstr()32 {33 fgets(arr,sizeof(arr),stdin);34 arr[strlen(arr)-1]='\0';35 36 }37 void splidcomandstr()38 {39  40 str[0]=strtok(arr,SEP);41 int index=1;42 while(str[index++]=strtok(NULL,SEP));43 }44 int main()45 {46   getcommandline();47   getcommandstr();48   splidcomandstr();49   int i;50   for( i=0;i<32;i++)51   {printf("%s ",str[i]);}52 53 54 }

5.进程替换

本来要先处理是否是内建命令的,但是我们先可以看这步,我们在第3步中,将分割开的指令字符串地址放在了str指针数组中,相当于命令行参数表,这一步我们要将对应的命令让子进程替换成对应命令的实现,大家可以去看一下之前的文章
进程的替换

针对我们已经有的命令行参数表
在这里插入图片描述
我们要使用的函数为
int execvp(const char *file, char *const argv[])
而str[0]是指令的地址,所以他是第一个参数,第二个参数为命令行参数表,所以是str

头文件

#include <unistd.h>

由于我们要用子进程替换,所以我们会使用到fork函数来创建子进程,在子进程中调用 execvp函数,父进程需要等待回收子进程的pcb的结构内的退出码,以及退出状态,将子进程的内存释放,所以需要使用waitpid函数,这一模块的代码也在进程替换那篇文章讲过

   48 void finishcommand()49 {50 int id=fork();51 if(id>0)52 {53 execvp(str[0],str);54 exit(exitcode);55 }56 int status=0;57 int ref=waitpid(id,&status,0);58 if(ref>0)59 {60 61 exitcode=WEXITSTATUS(status);62 if(exitcode!=0)printf("%s:%s:%d\n",str[0],strerror(exitcode),exitcode);63 }64                                                                                                                  65 }

此时我们已经可以用非内建命令了,为了让我们一直可以在我们自己写的命令行里跑指令,我们就加一个while循环
效果展示
top
在这里插入图片描述
ls
在这里插入图片描述


修改bug:
bug1:如果这里gethostname()报错的话,可能和库里面的名字冲突了,修改gethostname为gethost()
bug 2:如果这里陷入死循环,是因为fork给子进程返回的是0,这里写错了

   48 void finishcommand()49 {50 int id=fork();51 if(id==0)52 {53 execvp(str[0],str);54 exit(exitcode);55 }56 int status=0;57 int ref=waitpid(id,&status,0);58 if(ref>0)59 {60 61 exitcode=WEXITSTATUS(status);62 if(exitcode!=0)printf("%s:%s:%d\n",str[0],strerror(exitcode),exitcode);63 }64                                                                                                                  65 }

当前步骤代码展示

  1 #include<stdio.h>2 #include <stdlib.h>3 #include<string.h>4 #include <unistd.h>5 #include <sys/types.h>      6 #include <sys/wait.h>7 #include<errno.h>8 char arr[512];9 #define NUM 3210 char* str[NUM];11 #define SEP " "12 int exitcode=0;13 char*getname()14 {15 char *name=getenv("USER");16 if(name==NULL)return NULL;17 return name;18 }19 char*gethost()20 {21 char*hostname=getenv("HOSTNAME");                                                                                  22 if(hostname==NULL)return NULL;23 return hostname;24 }25 char*getpwd()26 {27 char*pwd=getenv("PWD");28 if(pwd==NULL)return NULL;29 return pwd;30 }                                                                                                                  31 void getcommandline()32 {33  printf("[%s@%s %s]$",getname(),gethost(),getpwd());34 }35 void getcommandstr()36 {37 fgets(arr,sizeof(arr),stdin);38 arr[strlen(arr)-1]='\0';39 40 }41 void splidcomandstr()42 {43  44 str[0]=strtok(arr,SEP);45 int index=1;46 while((str[index++]=strtok(NULL,SEP)));47 }48 void finishcommand()49 {50 int id=fork();51 if(id==0)52 {53 execvp(str[0],str);54 exit(exitcode);                                                                                                    55 }56 int status=0;57 int ref=waitpid(id,&status,0);58 if(ref>0)59 {60 61 exitcode=WEXITSTATUS(status);62 if(exitcode!=0)printf("%s:%s:%d\n",str[0],strerror(exitcode),exitcode);63 }64 65 }66 int main()67 {68 int quit=0;69   while(!quit)70   { getcommandline();71   getcommandstr();72   splidcomandstr();73   finishcommand();74 75 }}

4.处理内建命令

在处理内建命令前,需要处理一下命令行提示的路径,我们需要修改为
在这里插入图片描述

只保留最后一个/后面的路径,所以我们要修改一下getpwd函数

 25 char*getpwd()  26 {   27 char*pwd=getenv("PWD");                                       28 if(pwd==NULL)return NULL;                                     29 char*p=pwd+strlen(pwd)-1;                                     30    while((*p)!='/')                                           31    {                                                          32                                                               33    p--;                                                       34                                                               35    }                                                          36    return p+1;                                                                                                     37 } 

让p指针指向最后一个字母,然后遍历找最后一个‘/’,找到返回下一个位置的地址
在这里插入图片描述
这里的~就是家目录zjw


在这里插入图片描述
我们发现在命令行输入cd命令,怎么路径不变呢??
是因为执行命令的是子进程,改变路径的也是子进程,而我们打印的命令行是父进程在环境变量中拿到的值,子进程改变的环境变量不会写入环境变量表中
在这里插入图片描述

因为进程具有独立性


 90 int Built_incommands()                                                                                             91   { int yes=0;92   char* built=str[0];                                                                                              93   if(strcmp(built,"cd")==0)94   {95    yes=1;96    cd();97   }98   else if(strcmp(built,"echo")==0&&strcmp(str[1],"$?")==0)99   {
100   yes=1;
101  printf("%d\n",exitcode);
102   exitcode=0;
103   }
104  
105  return yes;
106  
107  }

处理内建命令,如果第一个字符串为cd的话,yes置1,说明是内建命令,就不执行子进程的命令了,直接continue;

 78  void cd()79   {80    char* path=str[1];81    if(path==NULL)path=gethome();82     chdir(path);83     84    char cwd[1024];85     char temp[1024];86     getcwd(temp,sizeof(temp));87     snprintf(cwd,sizeof(cwd),"PWD=%s",temp);88     putenv(cwd);                                                                                                         89   }

在cd函数内 如果输入的指令cd 没有加指令,所以str[1]就为NULL,path保存家目录地址,chdir函数为修改当前进程的路径,但是没有导入到环境变量中
在这里插入图片描述

pwd为查看当前路径.而命令行提示中的路径为环境变量中的路径,getcwd会将当前进程的绝对路径保存在temp字符串中
在这里插入图片描述
现在要做的是将temp字符串按照环境变量格式导入到环境变量表去.
使用 snprintf(cwd,sizeof(cwd),“PWD=%s”,temp);
将temp的内容按PWD=temp的格式放到cwd字符串中去。
然后使用putenv导入环境变量。
这里为什么不直接将path按照环境变量格式导入到环境变量表去.因为cd …的话,path就是…了,如果导进去的话,命令行参数的路径就成为…了
在这里插入图片描述

这里为了防止命令行参数中到家目录后在cd…到根目录,路径消失,如果getpwd()获取的字符串长度为1的话,就说明到根目录了,就不会消失了

 void getcommandline()  {printf("[%s@%s %s]$",getname(),gethost(),strlen(getpwd())==1? "/" : getpwd());                                    }

在这里插入图片描述

这里发现怎么还是不在呢??
因为getpwd是从最后一个/的下一个位置返回的,所以没有/了,所以我们直接在getpwd中返回/位置就行了,不要+1了,这时候strlen(getpwd())在家目录下就是1了,然后不在家目录下,就让返回的地址+1即可

 30 char*getpwd()31 {32 char*pwd=getenv("PWD");33 if(pwd==NULL)return NULL;34 char*p=pwd+strlen(pwd)-1;35    while((*p)!='/')36    {37 38    p--;39 40    }41    return p;                                                                                                       42 }
43 void getcommandline()44 {45  printf("[%s@%s %s]$",getname(),gethost(),strlen(getpwd())==1? "/" :       getpwd()+1);                                  46 }

在这里插入图片描述
这样子就好了


在处理内建命令时,我们会使用 echo $?来查看子进程给父进程的退出码,我们在 Built_incommands() 函数中也需要处理,如果命令行参数第一个字符串为echo,并且第二个字符串为 $ ?,我们直接打印退出码即可,为了确保下次退出时,退出码重置为0.
在 finishcommand()中父进程得到子进程的退出码后,如果退出码不为0的话,我们使用strerror将对应的错误码对应的原因打印出啦
头文件为

#include<errno.h>

6 源码分享

 1 #include<stdio.h>2 #include <stdlib.h>3 #include<string.h>4 #include <unistd.h>5 #include <sys/types.h>      6 #include <sys/wait.h>7 #include<errno.h>8 char arr[512];9 #define NUM 3210 char* str[NUM];11 #define SEP " "12 int exitcode=0;13 char*getname()14 {15 char *name=getenv("USER");16 if(name==NULL)return NULL;17 return name;18 }19 char*gethost()20 {21 char*hostname=getenv("HOSTNAME");                                                                                  22 if(hostname==NULL)return NULL;23 return hostname;24 }25  char*gethome()                                                                                                  {26   char*home=getenv("HOME");27   if(home==NULL)return NULL;28      return home;29  }30 char*getpwd()                                                                                                      31 {32 char*pwd=getenv("PWD");33 if(pwd==NULL)return NULL;34 char*p=pwd+strlen(pwd)-1;35    while((*p)!='/')36    {37     38    p--;39 40    }41    return p;42 }43 void getcommandline()44 {45  printf("[%s@%s %s]$",getname(),gethost(),strlen(getpwd())==1? "/" : getpwd()+1);46 }47 void getcommandstr()48 {49 fgets(arr,sizeof(arr),stdin);50 arr[strlen(arr)-1]='\0';51 52 }53 void splidcomandstr()54 {                                                                                                                  55  56 str[0]=strtok(arr,SEP);57 int index=1;58 while((str[index++]=strtok(NULL,SEP)));59 }60 void finishcommand()61 {62 int id=fork();63 if(id==0)64 {65 execvp(str[0],str);66 exit(exitcode);67 }68 int status=0;69 int ref=waitpid(id,&status,0);70 if(ref>0)71 {72 73 exitcode=WEXITSTATUS(status);74 if(exitcode!=0)printf("%s:%s:%d\n",str[0],strerror(exitcode),exitcode);75 }76 77 }78  void cd()                                                                                                         79   {80    char* path=str[1];81    if(path==NULL)path=gethome();82     chdir(path);83 84  85    char cwd[1024];86     char temp[1024];87    getcwd(temp,sizeof(temp));88    89     snprintf(cwd,sizeof(cwd),"PWD=%s",temp);90     putenv(cwd);                                                                                                         91   }92 int Built_incommands()                                                                                             93   { int yes=0;94   char* built=str[0];95   if(strcmp(built,"cd")==0)96   {97    yes=1;97    yes=1;98    cd();99   }
100   else if(strcmp(built,"echo")==0&&strcmp(str[1],"$?")==0)
101   {
102   yes=1;                                                                                                           
103  printf("%d\n",exitcode);
104   exitcode=0;
105   }
106  
107  return yes;
108  
109  }
110 int main()
111 {
112 int quit=0;
113   while(!quit)
114   { getcommandline();
115   getcommandstr();
116   splidcomandstr();
117   if(Built_incommands())
118     continue;
119   finishcommand();
120   }
121 }

7.增加重定向功能

思路:我们将第二步处理过的指令以及选项的字符串拷贝到另一个字符串数组(copyarr)中,我们要遍历这个数组,找>(输出重定向),找>>(追加输出重定向),找<(输入重定向),定义全局变量表示当前指令以及选项中到底是哪种重定向方式

 char copyarr[512];#define None_Redir 0#define In_Redir 1#define Out_Redir 2#define App_Redir 3int redir_type=None_Redir;//首先还没有遍历无重定向char *filename=NULL; //存放字符串中重定向后面的文件名的起始地址
void redirection()
142 {
143 int begin=0;
144 int end=strlen(copyarr);
145 while(begin<end)
146 {
147   if(copyarr[begin]=='>')
148   {
149    if(copyarr[begin+1]=='>')
150    {
151     copyarr[begin++]=0;
152     begin++;
153     redir_type=App_Redir;                                                                                          
154     while(copyarr[begin]==' ')
155      {begin++;}
156    filename=copyarr+begin;
157    }
158    else
159    { copyarr[begin++]=0;
160      redir_type=Out_Redir;
161      while(copyarr[begin]==' ')                                                 
162       {begin++;}
163      filename=copyarr+begin;
164    }
165 
166   }
167   else if(copyarr[begin]=='<')
168   {
169     copyarr[begin++]=0;  
170      redir_type=In_Redir;
171        while(copyarr[begin]==' ')                                                                                  
172        {begin++;}
173       filename=copyarr+begin;
174 
175 
176 
177   }
178   else 
179   {
180    begin++;
181 
182 
183 
184 
185   }
186   
187 }
188 memset(arr,'\0',512);
189 memcpy(arr,copyarr,strlen(copyarr));
190 }

上面这个函数就是读取指令字符串,将指令以及选项和后面的文件名分隔开,由于已经在第一个>或<或>>的第一个位置放0,所以处理后的copyarr是前面的指令带选项,而filename保存的是后面文件的起始地址,因为我们在第三步要分隔第二步处理好的字符串,所以我们再没有重定向标识,已经文件名的字符串又拷贝回arr中等待第三步分割
在这里插入图片描述
由于让子进程做进程替换不会影响父进程打开的文件,所以我们需要在子进程替换前进行处理重定向部分内容.

 69 void finishcommand()70 {71 int id=fork();72 if(id==0)73 {74 if(filename!=NULL)75 {76 if(redir_type==App_Redir)77 {78 int fd=open(filename,O_WRONLY|O_CREAT|O_APPEND,0666);79 dup2(fd,1);80 }81 else if(redir_type==Out_Redir)                                                                                     82 {83 int fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC,0666);84   dup2(fd,1); 85 }86 else if(redir_type==In_Redir)87 {88 89 int fd=open(filename,O_RDONLY);90 dup2(fd,0); 91 }92 else93 {}                                                                                                                 94 }95 execvp(str[0],str);96 exit(exitcode);97 }98 int status=0;99 int ref=waitpid(id,&status,0);
100 if(ref>0)
101 {
102 
103 exitcode=WEXITSTATUS(status);
104 if(exitcode!=0)printf("%s:%s:%d\n",str[0],strerror(exitcode),exitcode);
105 }
106 
107 }

这里说一下dup2这个函数,具体放在下一篇博客里面
在这里插入图片描述

8.源码分享终

  1 #include<stdio.h>2 #include <stdlib.h>3 #include<string.h>4 #include <unistd.h>5 #include <sys/types.h>6 #include <sys/wait.h>7 #include<errno.h>8 #include <sys/stat.h>9 #include <fcntl.h>10 char arr[512];11 char copyarr[512];12 #define NUM 3213 char* str[NUM];14 #define SEP " "15 #define None_Redir 016 #define In_Redir 117 #define Out_Redir 218 #define App_Redir 319 int redir_type=None_Redir;20 int exitcode=0;21 char *filename=NULL;                                                                                               22 char*getname()23 {24 char *name=getenv("USER");25 if(name==NULL)return NULL;26 return name;27 }28 char*gethost()29 {30 char*hostname=getenv("HOSTNAME");                                                                                  31 if(hostname==NULL)return NULL;32 return hostname;33 }34  char*gethome()                                                                                                  {35   char*home=getenv("HOME");36   if(home==NULL)return NULL;37      return home;38  }39 char*getpwd()40 {41 char*pwd=getenv("PWD");42 if(pwd==NULL)return NULL;43 char*p=pwd+strlen(pwd)-1;44    while((*p)!='/')45    {46     47    p--;48 49    }50    return p;51 }                                                                                                                  52 void getcommandline()53 {54  printf("[%s@%s %s]$",getname(),gethost(),strlen(getpwd())==1? "/" : getpwd()+1);55 }56 void getcommandstr()57 {58 fgets(arr,sizeof(arr),stdin);59 arr[strlen(arr)-1]='\0';60 memcpy(copyarr,arr,strlen(arr));61 }62 void splidcomandstr()63 {64  65 str[0]=strtok(arr,SEP);66 int index=1;67 while((str[index++]=strtok(NULL,SEP)));68 }69 void finishcommand()70 {71 int id=fork();72 if(id==0)73 {74 if(filename!=NULL)75 {76 if(redir_type==App_Redir)77 {78 int fd=open(filename,O_WRONLY|O_CREAT|O_APPEND,0666);79 dup2(fd,1);80 }81 else if(redir_type==Out_Redir)82 {83 int fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC,0666);84   dup2(fd,1);                                                                                                      85 }86 else if(redir_type==In_Redir)87 {88 89 int fd=open(filename,O_RDONLY);90 dup2(fd,0); 91 }92 else93 {}94 }95 execvp(str[0],str);96 exit(exitcode);97 }98 int status=0;99 int ref=waitpid(id,&status,0);
100 if(ref>0)
101 {
102                                                                                                                    
103 exitcode=WEXITSTATUS(status);
104 if(exitcode!=0)printf("%s:%s:%d\n",str[0],strerror(exitcode),exitcode);
105 }
106 
107 }
108  void cd()
109   {
110    char* path=str[1];
111    if(path==NULL)path=gethome();
112     chdir(path);
113     
114  
115    char cwd[1024];
116     
117     char temp[1024];
118    getcwd(temp,sizeof(temp));
119    
120     snprintf(cwd,sizeof(cwd),"PWD=%s",temp);                                                                       
121     putenv(cwd);                                                                                                         
122   }
123 int Built_incommands()                                                                                             
124   { int yes=0;
125   char* built=str[0];
126   if(strcmp(built,"cd")==0)
127   {
128    yes=1;
129    cd();
130   }
131   else if(strcmp(built,"echo")==0&&strcmp(str[1],"$?")==0)
132   {
133   yes=1;
134  printf("%d\n",exitcode);
135   exitcode=0;
136   }
137  
138  return yes;
139  
140  }
141 void redirection()
142 {
143 int begin=0;
144 int end=strlen(copyarr);                                                                                           
145 while(begin<end)
146 {
147   if(copyarr[begin]=='>')
148   {
149    if(copyarr[begin+1]=='>')
150    {
151     copyarr[begin++]=0;
152     begin++;
153     redir_type=App_Redir;
154     while(copyarr[begin]==' ')
155      {begin++;}
156    filename=copyarr+begin;
157    }
158    else
159    { copyarr[begin++]=0;
160      redir_type=Out_Redir;
161      while(copyarr[begin]==' ')                                                 
162       {begin++;}
163      filename=copyarr+begin;
164    }
165 
166   }
167   else if(copyarr[begin]=='<')
168   {                                                                                                                
169     copyarr[begin++]=0;  
170      redir_type=In_Redir;
171        while(copyarr[begin]==' ')                                                 
172        {begin++;}
173       filename=copyarr+begin;
174 
175 
176 
177   }
178   else 
179   {
180    begin++;
181 
182 
183 
184 
185   }
186   
187 }
188 memset(arr,'\0',512);
189 memcpy(arr,copyarr,strlen(copyarr));
190 }
191 int main()
192 {
193    int quit=0;
194   while(!quit)
195   { filename=NULL;                                                                                                 
196     memset(copyarr,'\0',512);
197     redir_type=None_Redir;
198   getcommandline();
199   getcommandstr();
200   redirection(); 
201   splidcomandstr();
202   
203  // printf("redir_type:%d\n",redir_type);
204  // printf("filename:%s\n",filename);
205   if(Built_incommands())
206     continue;
207   finishcommand();
208   }
209 }

输出重定向
在这里插入图片描述

追加重定向
在这里插入图片描述

输入重定向
在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/792270.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux 文件相关命令

一、查看文件命令 1&#xff09;浏览文件less 默认查看文件的前 10 行。 less /etc/services ##功能说明&#xff1a; #1.默认打开首屏内容 #2.按【回车】按行访问 #3.按【空格】按屏访问 #4.【从上向下】搜索用/111,搜索包含111的内容&#xff0c;此时按n继续向下搜&#x…

JAVAEE之IoCDI

Spring 是⼀个 IoC&#xff08;控制反转&#xff09;容器&#xff0c;作为容器, 那么它就具备两个最基础的功能&#xff1a; • 存 • 取 Spring 容器管理的主要是对象, 这些对象, 我们称之为"Bean". 我们把这些对象交由Spring管理, 由 Spring来负责对象的创建…

想学网络安全,从哪里开始?网络安全的学习路线

网络安全学习路线&#xff1a; 想学习网络安全专业的知识&#xff0c;想当黑客&#xff0c;但是不知道该从哪里开始学。 我给你一个路线&#xff01; 清晰图片和大纲&#xff1a;https://docs.qq.com/doc/DU1lpVFpSbWVrd2p3

面试官:为什么忘记密码要重置,而不是告诉我原密码?

前端训练营&#xff1a;1v1私教&#xff0c;终身辅导计划&#xff0c;帮你拿到满意的 offer。 已帮助数百位同学拿到了中大厂 offer。欢迎来撩~~~~~~~~ Hello&#xff0c;大家好&#xff0c;我是 Sunday。 最近有个同学在面试中遇到了一个很有意思的问题&#xff0c;我相信大多…

蓝桥杯23年第十四届省赛-异或和之和|拆位、贡献法

题目链接&#xff1a; 蓝桥杯2023年第十四届省赛真题-异或和之和 - C语言网 (dotcpp.com) 1.异或和之和 - 蓝桥云课 (lanqiao.cn) 参考题解&#xff1a; 蓝桥杯真题讲解&#xff1a;异或和之和 &#xff08;拆位、贡献法&#xff09;-CSDN博客 洛谷P9236 [蓝桥杯 2023 省 A]…

【T5中的激活函数】GLU Variants Improve Transformer

【mT5中的激活函数】GLU Variants Improve Transformer 论文信息 阅读评价 Abstract Introduction Gated Linear Units (GLU) and Variants Experiments on Text-to-Text Transfer Transformer (T5) Conclusion 论文信息 名称内容论文标题GLU Variants Improve Transfo…

flutter获取手机中的系统路径信息

https://www.bilibili.com/video/BV1wE421g7sw获取系统中的路径 获取系统中的路径&#xff0c;并在这个路径中创建一个文本文件【str.txt】 然后进行写入【str.txt】 再读取这个文件【str.txt】 手机没有开通root权限无法看到写入到【应用程序文档目录】路径中的文件 用来…

MySQL故障排查与优化

一、MySQL故障排查 1.1 故障现象与解决方法 1.1.1 故障1 1.1.2 故障2 1.1.3 故障3 1.1.4 故障4 1.1.5 故障5 1.1.6 故障6 1.1.7 故障7​ 1.1.8 故障8 1.1.9 MySQL 主从故障排查 二、MySQL优化 2.1 硬件方面 2.2 查询优化 一、MySQL故障排查 1.1 故障现象与解决方…

【考研经验贴】24考研860软件工程佛系上岸经验分享【丰富简历、初复试攻略、导师志愿、资料汇总】

&#x1f60a;你好&#xff0c;我是小航&#xff0c;一个正在变秃、变强的文艺倾年。 &#x1f514;本文讲解24考研860软件工程佛系上岸经验分享【丰富简历、初复试攻略、导师志愿、资料汇总】&#xff0c;期待与你一同探索、学习、进步&#xff0c;一起卷起来叭&#xff01; 目…

玩转C语言——文件操作、预处理、编译、链接

前言&#xff1a; 经过前面的学习&#xff0c;我们已经对C语言的语法学习完毕了&#xff0c;今天&#xff0c;我们这节内容是为了修炼内功&#xff0c;为以后的学习打下一个坚实基础。话不多说&#xff0c;开始我们今天的学习吧&#xff01; 一、文件操作 1.⼆进制⽂件和⽂本⽂…

一文了解低功耗蓝牙BLE

低功耗蓝牙技术可以构建两种类型的设备:双模设备和单模设备。双模设备既支持经典蓝牙又支持低功耗蓝牙。单模设备只支持低功耗蓝牙。还有仅支持经典蓝牙的设备。 在链路层,设备被分为广播者、扫描者、从设备和主设备。广播者是传输数据包的设备,扫描者是接收广播者的数据包…

C语言 | Leetcode C语言题解之第10题正则表达式匹配

题目&#xff1a; 题解&#xff1a; bool isMatch(char* s, char* p) {int m strlen(s);int n strlen(p);// dp[i][j] 表示 s 的前 i 个字符和 p 的前 j 个字符是否匹配bool dp[m 1][n 1];memset(dp, false, sizeof(dp));dp[0][0] true; // 空字符串和空模式匹配// 处理 …

00-JAVA基础-javassist字节码操作

字节码操作 什么是字节码 Java字节码&#xff08;Java bytecode&#xff09;是Java虚拟机&#xff08;JVM&#xff09;执行的一种虚拟指令格式。它是由Java编译器生成的&#xff0c;基于栈的指令集&#xff0c;用于在Java虚拟机上执行。字节码文件包含了JVM能够识别的指令&am…

【JSON2WEB】 12基于Amis-admin的动态导航菜单树

【JSON2WEB】01 WEB管理信息系统架构设计 【JSON2WEB】02 JSON2WEB初步UI设计 【JSON2WEB】03 go的模板包html/template的使用 【JSON2WEB】04 amis低代码前端框架介绍 【JSON2WEB】05 前端开发三件套 HTML CSS JavaScript 速成 【JSON2WEB】06 JSON2WEB前端框架搭建 【J…

Flume 拦截器概念及自定义拦截器的运用

文章目录 Flume 拦截器拦截器的作用拦截器运用1.创建项目2.实现拦截器接口3.编写事件处理逻辑4.拦截器构建5.打包与上传6.编写配置文件7.测试运行 Flume 拦截器 在 Flume 中&#xff0c;拦截器&#xff08;Interceptors&#xff09;是一种可以在事件传输过程中拦截、处理和修改…

FreeRtos入门-4 事件组与同步点

事件组 事件组 同步点 创建 xEventGroupCalc xEventGroupCreate();//1&#xff0c;创建事件组 xEventGroupSyc xEventGroupCreate() 设置 xEventGroupSetBits(xEventGroupCalc,(1<<0));//设置事件组bit0 位 xEventGroupSync(xEventGroupSyc,BUSYING,ALL,portMAX…

VB 通过COM接口解析PSD文件

最近有PS测评的需求&#xff0c;故而想到了解析psd文件&#xff0c;目的就是为了获取文档信息和图层信息&#xff1b;获取PS的图像信息有很多方式&#xff0c;有过程性的&#xff0c;比如监听PS的各种操作事件&#xff1b;有结果性的&#xff0c;比如本文写的解析PSD文件。 0.…

使用pip安装geopandas(24.4更新)

geopandas是我们用Python进行地理分析常用的库&#xff0c;在数据处理、分析、制图等场景中有着极为广泛的应用&#xff0c;但是在安装过程中会出现各种问题。​geopandas的安装方式有很多&#xff0c;今天我们选取较为简单的pip来进行geopandas的安装。 ​首先&#xff0c;我…

内部类(InnerClass)

概述 什么是内部类 将一个类A定义在另一个类B里面&#xff0c;里面的那个类A就称为内部类&#xff08;InnerClass&#xff09;&#xff0c;类B则称为外部类&#xff08;OuterClass&#xff09;。 为什么要声明内部类呢 具体来说&#xff0c;当一个事物A的内部&#xff0c;还有…