當我們學過了進程替換之后,本篇文章可以根據(jù)進程替換的知識帶你自主實現(xiàn)一個shell命令行
實現(xiàn)步驟
1.顯示命令行提示
2.讀取輸入指令以及對應選項
3.分割第二步的指令以及選項到命令行參數(shù)表中
4.處理內(nèi)建命令
5.進程替換
1.顯示命令行提示
我們通過觀察bash的命令行提示發(fā)現(xiàn)他是由三部分組成的
1.用戶名
2.主機名
3.當前路徑
而這三部分的信息都對應保存在我們的環(huán)境變量中
我們可以通過env指令查到
這里要介紹一個getenv函數(shù),他可以將對應的環(huán)境變量對應的字符串打印出來,返回對應字符串的起始地址
我們可以封裝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)境變量)
我們根據(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 }
效果展示
2.讀取輸入指令以及對應選項
為了處理我們輸入的指令,我們需要將輸入的指令以及選項保存在一個字符串中,就類比為命令行參數(shù)表.
我們應該如何讀取字符串呢??
試想一下我們可以用scanf讀字符串嗎?
答案是不能的,因為我們在輸入指令以及選項時,會帶空格分割開來,而scanf會將空格作為分隔符,不會讀取進來。
所以我們要使用的是fgets
#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ù)組
為了區(qū)別系統(tǒng)的和我們自己實現(xiàn)的,我們將]后面的$換成¥
效果展示
當前步驟代碼展示
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
我們要分隔開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)結束
效果展示
當前步驟代碼展示
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ù)表
我們要使用的函數(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
ls
修改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)建命令前,需要處理一下命令行提示的路徑,我們需要修改為
只保留最后一個/后面的路徑,所以我們要修改一下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指針指向最后一個字母,然后遍歷找最后一個‘/’,找到返回下一個位置的地址
這里的~就是家目錄zjw
我們發(fā)現(xiàn)在命令行輸入cd命令,怎么路徑不變呢??
是因為執(zhí)行命令的是子進程,改變路徑的也是子進程,而我們打印的命令行是父進程在環(huán)境變量中拿到的值,子進程改變的環(huán)境變量不會寫入環(huán)境變量表中
因為進程具有獨立性
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)境變量中
pwd為查看當前路徑.而命令行提示中的路徑為環(huán)境變量中的路徑,getcwd會將當前進程的絕對路徑保存在temp字符串中
現(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ù)的路徑就成為…了
這里為了防止命令行參數(shù)中到家目錄后在cd…到根目錄,路徑消失,如果getpwd()獲取的字符串長度為1的話,就說明到根目錄了,就不會消失了
void getcommandline()
{
printf("[%s@%s %s]$",getname(),gethost(),strlen(getpwd())==1? "/" : getpwd());
}
這里發(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 }
這樣子就好了
在處理內(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中等待第三步分割
由于讓子進程做進程替換不會影響父進程打開的文件,所以我們需要在子進程替換前進行處理重定向部分內(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ù),具體放在下一篇博客里面
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 }
輸出重定向
追加重定向文章來源:http://www.zghlxwxcb.cn/news/detail-858533.html
輸入重定向文章來源地址http://www.zghlxwxcb.cn/news/detail-858533.html
到了這里,關于【linux】進程替換的應用|shell解釋器的實現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!