一、进程程序替换



进程程序替换:


进程程序替换过程只是将代码和数据替换,并没有创建新的进程,pid不变。


Linux操作系统中的shell就是运用这个原理处理客户请求的,不是每个请求都是shell亲力亲为的,所以shell会创建子程序替换他,在实现shell的过程中我们会用到exec函数,所以我们先了解一下exec函数族并对其每个的用法用代码实现一遍。




exec函数家族包括6种:execl、execlp、execle、execv、execvp、execve,如下:




进程程序替换以及简易shell的实现_进程替换


进程程序替换以及简易shell的实现_自主shell_02


它们有什么区别呢?


函数名中:


l(list):参数采用列表


v(vector):参数采用数组


p(path):由p自动搜索环境变量(path)


e(env):表示自己维护环境变量


所以,各函数的区别如下:


进程程序替换以及简易shell的实现_自主shell_03


这些函数如果调用成功,则加载新的程序从启动代码开始执行,不再返回;

如果调用出错则返回-1;


也就是说exec函数只有出错返回值,没有成功返回值。


exec函数应用举例:



#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>

int main(){
char *const argv[]={"ps","-ef",NULL};
char *const envp[]={"PATH=/bin:/usr/bin","TERM=console",NULL};

execl("/bin/ps","ps","-ef",NULL);

//带p,可以使用环境变量PATH,无需写全路径
execlp("ps","ps","-ef",NULL);

//带e,需要自己组装环境变量
execle("ps","ps","-ef",NULL,envp);

execv("/bin/ps",argv);

//带p,可以使用环境变量PATH,无需写全路径
execvp("ps",argv);

//带e,需要自己组装环境变量
execve("/bin/ps",argv,envp);

exit(0);
}


其实,只有execve是真正的系统调用,其他五个函数最终都调用execve。




二、编写一个简易shell




1、看一下简易shell的编写





进程程序替换以及简易shell的实现_进程替换_04



2、了解shell的工作过程



时间从左向右,如图:



进程程序替换以及简易shell的实现_自主shell_05


shell从用户读入字符串“ls",shell建立一个新的进程,用来运行ls的程序并等待此进程结束。



然后shell读取新的一行输入,建立一个新的进程,在这个进程运行程序,并等待其结束。


所以我们知道,要写一个shell,需要循环以下过程:


获取命令行


b)解析命令行


c)建立一个子进程(fork)


d)替换子进程(execvp)


e)父进程等待子进程退出(wait)


实现代码:


1 #include<unistd.h>
2 #include<sys/wait.h>
3 #include<stdio.h>
4 #include<stdlib.h>
5 #include<string.h>
6
7 char *argv[8];
8 int argc=0;
9
10 void do_parse(char *buf){
11 int i;
12 int status=0;
13
14 for(argc=i=0;buf[i];i++){
15 if(!isspace(buf[i])&&status==0){
16 argv[argc++]=buf+i;
17 status=1;
18 }
19 else if(isspace(buf[i])){
20 status=0;
21 buf[i]=0;
22 }
23 }
24 argv[argc]=NULL;
25 }
26
27 void do_execute(void){
28 pid_t pid=fork();
29
30 switch(pid){
31 case -1:
32 perror("fork");
33 exit(EXIT_FAILURE);
34 break;
35 case 0:
36 execvp(argv[0],argv);
37 perror("execvp");
38 exit(EXIT_FAILURE);
39 default:
40 {
41 int st;
42 while(wait(&st)!=pid)
43 ;
44 }
45 }
46 }
47
48 int main(){
49 char buf[1024]={};
50 while(1){
51 printf("myshell> ");
52 scanf("%[^\n]%*c",buf);
53 do_parse(buf);
54 do_execute();
55 }
56 }


结果如下:



进程程序替换以及简易shell的实现_#include_06