替换原理:
用fork创建进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换。从新进程的启动例程开始执行,调用exec函数并不创建新进程,所以调用exec函数前后进程的id并未改变。
替换函数:
有六种以exec开头的函数,统称exec函数:
#include<unistd.h>
int execl(const char*path,const char*arg)
int execlp(const char*file,const char*arg)
int execle(const char*path,const char*arg,...,char const envp[])
int execv(const char*path,char *const argv[])
int execvp(const char*file,char*const argv[])
int execve(const char*path,char* const argv[],char*const envp[])
这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。
如果调用出错则返回-1。
所以exec函数只有出错的返回值而没有成功的返回值。
这些函数原型看起来很容易混淆,但只要掌握了规律就很好记。
l(list):表示参数采用列表
v(vector):参数用数组
p(path):有p自动搜素环境变量path
e(env):表示自己维护的环境变量
事实上只有execve是真正的系统调用,其他几个函数最终都调用execve函数。
下面使用exec函数来实现一个简单的shell
直接上代码
1 //模拟shell写一个咱们自己的微型shell
2 //功能:myshell>ls
3 //能够执行各种命令
4 #include<stdio.h>
5 #include<unistd.h>
6 #include<stdlib.h>
7 #include<errno.h>
8 #include<string.h>
9 //1.获取终端输入
10 //2.解析输入(按空格解析到一个一个的命令参数)
11 //3.创建一个子进程
12 // 在子进程中经行程序替换,让子进程运行命令
13 //4.等待子进程运行完毕,收尸,获取退出状态码
14 int argc;
15 char* argv[32];
16 int param_parse(char *buff)
17 {
18 if(buff==NULL)
19 {
20 return -1;
21 }
22 char*ptr=buff;
23 char*tmp=ptr;
24 while((*ptr)!='\0')
25 {
26 //当遇到空格,并且下一个位置不是空格的时候
27 //将空格位置置‘\0’
28 //不过我们将使用argv[argc]来保存这个字符串的位置
29 if(*ptr==' '&&*(ptr+1)!=' ')
30 {
31 *ptr='\0';
32 argv[argc]=tmp;
33 tmp=ptr+1;
34 argc++;
35 }
36 ptr++;
37 }
38 argv[argc++]=tmp;
39 argv[argc]=NULL;
40 }
41 int exec_cmd()
42 {
43 int pid=0;
44 pid=fork();
45 if(pid<0)
46 {
47 return -1;
48 }
49 else if(pid==0)
50 {
51 execvp(argv[0],argv);
52 exit(0);
53 }
54 //父进程在这里必须等待子进程退出,来看看子进程为什么退出了
55 //是不是出现了什么错误,通过获取状态吗,并且转换一下退出码所
56 //对应的错误信息进行打印
57 int statu;
58 wait(&statu);
59 //判断子进程是否是代码运行完毕退出
60 if(WIFEXITED(statu))
61 {
62 //获取子进程的退出码,转换为文本信息打印
63 printf("%s",strerror(WEXITSTATUS(statu)));
64 }
65 return 0;
66 }
67 int main()
68 {
69 while(1)
70 {
71 printf("myshell>");
72 char buff[1024]={0};
73 //%[^\n]获取数据直到遇到\n为止
74 //%*c 清空缓冲区,数据都不要了
75 scanf("%[^\n]%*c",buff);
76 // printf("%s\n",buff);
77 param_parse(buff);
78 exec_cmd();
79 }
80
81 }