国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【linux】進程替換的應用|shell解釋器的實現(xiàn)

這篇具有很好參考價值的文章主要介紹了【linux】進程替換的應用|shell解釋器的實現(xiàn)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

當我們學過了進程替換之后,本篇文章可以根據(jù)進程替換的知識帶你自主實現(xiàn)一個shell命令行
實現(xiàn)步驟

1.顯示命令行提示
2.讀取輸入指令以及對應選項
3.分割第二步的指令以及選項到命令行參數(shù)表中
4.處理內(nèi)建命令
5.進程替換

1.顯示命令行提示

【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維

我們通過觀察bash的命令行提示發(fā)現(xiàn)他是由三部分組成的
1.用戶名
2.主機名
3.當前路徑
而這三部分的信息都對應保存在我們的環(huán)境變量中
我們可以通過env指令查到
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維

這里要介紹一個getenv函數(shù),他可以將對應的環(huán)境變量對應的字符串打印出來,返回對應字符串的起始地址
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維

我們可以封裝3個函數(shù)分別來獲取對應用戶名,主機名,路徑,這三個環(huán)境變量的字符串

//獲取用戶名的函數(shù)

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

name指針保存USER環(huán)境變量值對應字符串的首地址,如果為NULL ,就返回空(說明不存在這個環(huán)境變量)

//獲取主機名的函數(shù)

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

hostname指針保存HOSTNAME環(huán)境變量值對應字符串的首地址,如果為NULL ,就返回空(說明不存在這個環(huán)境變量)

//獲取路徑的函數(shù)

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

pwd指針保存PWD環(huán)境變量值對應字符串的首地址,如果為NULL,就返回空(說明不存在這個環(huán)境變量)


【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維
我們根據(jù)bash命令行的提示用getcommandline()函數(shù)來進行打印我們自己的命令行提示

 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 }

 

效果展示
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維


2.讀取輸入指令以及對應選項

為了處理我們輸入的指令,我們需要將輸入的指令以及選項保存在一個字符串中,就類比為命令行參數(shù)表.
我們應該如何讀取字符串呢??
試想一下我們可以用scanf讀字符串嗎?
答案是不能的,因為我們在輸入指令以及選項時,會帶空格分割開來,而scanf會將空格作為分隔符,不會讀取進來。
所以我們要使用的是fgets
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維

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

我們定義一個全局的字符串數(shù)組來保存輸入的指令以及選項的字符串

char arr[512];

因為我們要從屏幕上讀指令以及選項,所以fgets第三個參數(shù)為stdin(標準輸入流).
我們先將其讀到arr中,讀取512個字節(jié),然后使用strlen找到結尾添加‘\0’;比方說一個字符串為char arr[]=“abcdefg”;strlen(arr)=8; 我們需要在下標為strlen(arr)-1的位置添加一個‘\0’;
我們將獲取指令,選項字符串封裝在函數(shù)里面getcommandstr()

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

為了測試arr是否讀到,我們遍歷打印一下arr數(shù)組
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維

為了區(qū)別系統(tǒng)的和我們自己實現(xiàn)的,我們將]后面的$換成¥

效果展示
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維
當前步驟代碼展示

  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.分割第二步的指令以及選項到命令行參數(shù)表中

我們定義一個指針數(shù)組存放對應指令或者選項字符串的首地址,使用全局變量
默認可以存放32個字符串(指令或選項)的地址

#define NUM 32
char* str[NUM];

我們分隔字符串用strtok函數(shù),可以去看看我的這邊文章
strtok
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維

我們要分隔開arr數(shù)組,所以arr數(shù)組是第一個參數(shù),而要用空格分開

#define SEP ' ' 

而第二個參數(shù)我們傳SEP就好了
而返回的地址則是第一個空格之前的字符串指令
接著我們給第一個參數(shù)傳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]中,然后循環(huán)將每個分隔開的字符串指令放在str[index]中,然后讓index++,當arr字符串分割完之后,strtok返回NULL,給str[index],然后返回NULL,循環(huán)結束

效果展示
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維

當前步驟代碼展示

    1 #include<stdio.h>
    2 #include <stdlib.h>
    3 #include<string.h>
    4 char arr[512];
    5 #define NUM 32
    6 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.進程替換

本來要先處理是否是內(nèi)建命令的,但是我們先可以看這步,我們在第3步中,將分割開的指令字符串地址放在了str指針數(shù)組中,相當于命令行參數(shù)表,這一步我們要將對應的命令讓子進程替換成對應命令的實現(xiàn),大家可以去看一下之前的文章
進程的替換

針對我們已經(jīng)有的命令行參數(shù)表
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維
我們要使用的函數(shù)為
int execvp(const char *file, char *const argv[])
而str[0]是指令的地址,所以他是第一個參數(shù),第二個參數(shù)為命令行參數(shù)表,所以是str

頭文件

#include <unistd.h>

由于我們要用子進程替換,所以我們會使用到fork函數(shù)來創(chuàng)建子進程,在子進程中調(diào)用 execvp函數(shù),父進程需要等待回收子進程的pcb的結構內(nèi)的退出碼,以及退出狀態(tài),將子進程的內(nèi)存釋放,所以需要使用waitpid函數(shù),這一模塊的代碼也在進程替換那篇文章講過

   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 }

此時我們已經(jīng)可以用非內(nèi)建命令了,為了讓我們一直可以在我們自己寫的命令行里跑指令,我們就加一個while循環(huán)
效果展示
top
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維
ls
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維


修改bug:
bug1:如果這里gethostname()報錯的話,可能和庫里面的名字沖突了,修改gethostname為gethost()
bug 2:如果這里陷入死循環(huán),是因為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 32
 10 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.處理內(nèi)建命令

在處理內(nèi)建命令前,需要處理一下命令行提示的路徑,我們需要修改為
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維

只保留最后一個/后面的路徑,所以我們要修改一下getpwd函數(shù)

 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指針指向最后一個字母,然后遍歷找最后一個‘/’,找到返回下一個位置的地址
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維
這里的~就是家目錄zjw


【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維
我們發(fā)現(xiàn)在命令行輸入cd命令,怎么路徑不變呢??
是因為執(zhí)行命令的是子進程,改變路徑的也是子進程,而我們打印的命令行是父進程在環(huán)境變量中拿到的值,子進程改變的環(huán)境變量不會寫入環(huán)境變量表中
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維

因為進程具有獨立性


 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  }

處理內(nèi)建命令,如果第一個字符串為cd的話,yes置1,說明是內(nèi)建命令,就不執(zhí)行子進程的命令了,直接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函數(shù)內(nèi) 如果輸入的指令cd 沒有加指令,所以str[1]就為NULL,path保存家目錄地址,chdir函數(shù)為修改當前進程的路徑,但是沒有導入到環(huán)境變量中
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維

pwd為查看當前路徑.而命令行提示中的路徑為環(huán)境變量中的路徑,getcwd會將當前進程的絕對路徑保存在temp字符串中
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維
現(xiàn)在要做的是將temp字符串按照環(huán)境變量格式導入到環(huán)境變量表去.
使用 snprintf(cwd,sizeof(cwd),“PWD=%s”,temp);
將temp的內(nèi)容按PWD=temp的格式放到cwd字符串中去。
然后使用putenv導入環(huán)境變量。
這里為什么不直接將path按照環(huán)境變量格式導入到環(huán)境變量表去.因為cd …的話,path就是…了,如果導進去的話,命令行參數(shù)的路徑就成為…了
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維

這里為了防止命令行參數(shù)中到家目錄后在cd…到根目錄,路徑消失,如果getpwd()獲取的字符串長度為1的話,就說明到根目錄了,就不會消失了

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

【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維

這里發(fā)現(xiàn)怎么還是不在呢??
因為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 }

【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維
這樣子就好了


在處理內(nèi)建命令時,我們會使用 echo $?來查看子進程給父進程的退出碼,我們在 Built_incommands() 函數(shù)中也需要處理,如果命令行參數(shù)第一個字符串為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 32
 10 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.增加重定向功能

思路:我們將第二步處理過的指令以及選項的字符串拷貝到另一個字符串數(shù)組(copyarr)中,我們要遍歷這個數(shù)組,找>(輸出重定向),找>>(追加輸出重定向),找<(輸入重定向),定義全局變量表示當前指令以及選項中到底是哪種重定向方式

 char copyarr[512];
 #define None_Redir 0
 #define In_Redir 1
 #define Out_Redir 2
 #define App_Redir 3
 int 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 }

上面這個函數(shù)就是讀取指令字符串,將指令以及選項和后面的文件名分隔開,由于已經(jīng)在第一個>或<或>>的第一個位置放0,所以處理后的copyarr是前面的指令帶選項,而filename保存的是后面文件的起始地址,因為我們在第三步要分隔第二步處理好的字符串,所以我們再沒有重定向標識,已經(jīng)文件名的字符串又拷貝回arr中等待第三步分割
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維
由于讓子進程做進程替換不會影響父進程打開的文件,所以我們需要在子進程替換前進行處理重定向部分內(nèi)容.

 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 else
 93 {}                                                                                                                 
 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這個函數(shù),具體放在下一篇博客里面
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維

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 32
 13 char* str[NUM];
 14 #define SEP " "
 15 #define None_Redir 0
 16 #define In_Redir 1
 17 #define Out_Redir 2
 18 #define App_Redir 3
 19 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 else
 93 {}
 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 }





 

 

 

輸出重定向
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維

追加重定向
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維

輸入重定向
【linux】進程替換的應用|shell解釋器的實現(xiàn),Linux操作系統(tǒng),linux,chrome,運維文章來源地址http://www.zghlxwxcb.cn/news/detail-858533.html


到了這里,關于【linux】進程替換的應用|shell解釋器的實現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 【設計模式——學習筆記】23種設計模式——解釋器模式Interpreter(原理講解+應用場景介紹+案例介紹+Java代碼實現(xiàn))

    【設計模式——學習筆記】23種設計模式——解釋器模式Interpreter(原理講解+應用場景介紹+案例介紹+Java代碼實現(xiàn))

    通過解釋器模式來實現(xiàn)四則運算,如計算 a+b-c 的值,具體要求 先輸入表達式的形式,比如 a+b+c-d+e ,要求表達式的字母不能重復 在分別輸入 a,b,c,d,e 的值 最后求出結果 編寫一個方法,接收表達式的形式,然后根據(jù)用戶輸入的數(shù)值進行解析,得到結果 【分析】 如果加入新的

    2024年02月13日
    瀏覽(94)
  • 解鎖Spring Boot中的設計模式—02.解釋器模式:探索【解釋器模式】的奧秘與應用實踐!

    解鎖Spring Boot中的設計模式—02.解釋器模式:探索【解釋器模式】的奧秘與應用實踐!

    解釋器模式(Interpreter Pattern)是一種行為設計模式,它用于定義語言的文法,并且解釋語言中的表達式。在Java中,解釋器模式可以用于構建解釋器以解析特定的語言或表達式,如數(shù)學表達式、查詢語言等。 優(yōu)點: 靈活性: 解釋器模式可以 靈活地添加新的表達式和規(guī)則 ,因

    2024年02月19日
    瀏覽(95)
  • iThinkAir代碼解釋器對照Code Interpreter的應用案例

    iThinkAir代碼解釋器對照Code Interpreter的應用案例

    前幾天OpenAI對Plus會員開放了Code Interpreter功能,有人說是王炸,有人說是核彈級更新,也有人說是繼ChatGPT之后再度讓人感受到震撼和顛覆的產(chǎn)品。 時隔幾天,iThinkAir也創(chuàng)造了自己的\\\"代碼解釋器\\\"。 下面列舉iThinkAir\\\"代碼解釋器\\\"的十幾個應用案例,大家可以和Code Interpreter對照一

    2024年02月16日
    瀏覽(23)
  • linux文件上傳和下載、別名設置以及命令解釋器

    linux文件上傳和下載、別名設置以及命令解釋器

    (1) 它類似于 ftp 傳輸協(xié)議,屬于 ssh, 但它進行加密傳輸,相對 FTP 來講有更高的安全性 (2)用法 查看文件下載情況-將文件內(nèi)容copy到一個file1.txt文件中 將10.0.0.3的file1,txt文件上傳到當前文件的目錄下面 (3) 如果不知道遠程主機的目錄是什么樣, ?ls命令 可以列出10.0.

    2024年02月03日
    瀏覽(96)
  • Unity實現(xiàn)設計模式——解釋器模式

    Unity實現(xiàn)設計模式——解釋器模式

    解釋器模式(Interpreter Pattern)是一種按照規(guī)定語法進行解析的模式,現(xiàn)實項目中用得較少。 給定一門語言,定義它的文法的一種表示,并定義一個解釋器,該解釋器使用該表示來解釋語言中的句子。 下面用一個例子演示:將羅馬文字轉換為十進制的格式 解釋器基類 千位數(shù)

    2024年02月07日
    瀏覽(90)
  • Go和Java實現(xiàn)解釋器模式

    下面通過一個四則運算來說明解釋器模式的使用。 解釋器模式提供了評估語言的語法或表達式的方式,它屬于行為型模式。這種模式實現(xiàn)了一個表達式接口,該接口 解釋一個特定的上下文。這種模式被用在 SQL 解析、符號處理引擎等。 意圖:給定一個語言,定義它的文法表

    2024年02月12日
    瀏覽(20)
  • linux報錯 /bin/bash^M:解釋器錯誤:沒有那個文件或目錄

    linux報錯 /bin/bash^M:解釋器錯誤:沒有那個文件或目錄

    ??在Linux中運行腳本時,會出現(xiàn)linux報錯 /bin/bash^M:解釋器錯誤:沒有那個文件或目錄。這是因為我們將在Windows下編寫的腳本拷貝到Linux環(huán)境中運行時會出現(xiàn)運行不了的情況。主要還是Windows的換行符為rn,而Linux環(huán)境中的換行符號為n。 ??解決方法有: ??方法一: ??方法

    2024年02月13日
    瀏覽(97)
  • Linux 報錯 bash: /usr/bin/pip: 解釋器錯誤:沒有那個文件或目錄

    Linux 報錯 bash: /usr/bin/pip: 解釋器錯誤:沒有那個文件或目錄

    ? ? ? ? 今天在linux安裝python庫時,使用conda安裝太慢,換了鏡像源也沒用,于是使用pip安裝出現(xiàn)了解釋器錯誤:沒有那個文件或目錄的問題,記錄一下,或許對你有幫助。 ? ? ? ? ? ? ? ? 進入home/你的用戶名/anaconda3/envs/虛擬環(huán)境名字/bin/pip,不能直接用cd進去,可以使用na

    2024年01月18日
    瀏覽(162)
  • 【Linux】 /bin/bash^M: 壞的解釋器: 沒有那個文件或目錄[已解決]

    Windows 10 系統(tǒng)下編輯了一個shell腳本文件,然后copy到了遠程的Linux服務器。 運行 xxx.sh 文件時報錯 這個文件在Windows下編輯過,在Windows下每一行結尾是nr,而Linux下則是n,所以才會有多出來的r。 使用指令 會把 xxx.sh 中的r 替換成空白。

    2024年02月12日
    瀏覽(234)
  • 自己動手寫數(shù)據(jù)庫系統(tǒng):實現(xiàn)一個小型SQL解釋器(中)

    我們接上節(jié)內(nèi)容繼續(xù)完成SQL解釋器的代碼解析工作。下面我們實現(xiàn)對update語句的解析,其語法如下: UpdateCmd - INSERT | DELETE | MODIFY | CREATE Create - CreateTable | CreateView | CreateIndex Insert - INSERT INTO ID LEFT_PARAS FieldList RIGHT_PARAS VALUES LEFT_PARS ConstList RIGHT_PARAS FieldList - Field ( COMMA FieldList)?

    2024年02月12日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包