进程程序替换
- 替换原理
- 替换函数
- 实现一个简单的shell
- 主要过程
- 实现代码
替换原理
- 用fork创建子进程后执行的是和父进程相同的程序,若要执行不同的代码分支,子进程往往要调用一种exec函数以执行另一个程序;
- 当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行;
- 调用exec函数并不创建新进程,所以调用exec前后该进程的id并未改变。
替换函数
有六种以exec开头的函数,统称exec函数:
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[]);
其中,l(list) 表示参数采用列表,v(vector) 表示参数用数组,p(path) 表示有p自动搜索环境变量PATH,e(env) 表示自己维护环境变量。
实现一个简单的shell
主要过程
一个简单的shell,需要循环以下过程:
- 获取命令行-----fgets
- 解析命令行-----strtok
- 建立一个子进程(fork)
- 替换子进程(execvp)
- 父进程等待子进程退出(wait)
实现代码
#define SIZE 64
#define NUM 16
int main(){
char cmd[SIZE];
const char* cmd_line = "[gxr116@Centos_7 lesson2_1]$ ";
while(1){
cmd[0] = 0;
printf("%s", cmd_line);
fgets(cmd, SIZE, stdin); //命令行参数通过标准输入写入cmd
printf("%s", cmd);
cmd[strlen(cmd)-1] = '\0'; //把换行符替换为结束标志\0
char* argv[NUM]; //定义一个字符串数组,用来存放解析的结果
argv[0] = strtok(cmd, " "); //以空格来分割字符串,把第一个子串放在argv[0]中
int i= 1;
do{
argv[i] = strtok(NULL, " "); //分割剩下的字符串
if(argv[i] == NULL){
break;
}
i++;
}while(1);
//测试命令行参数是否能被正确解析
/*
int j = 0;
for( ; j<i; j++){
printf("argv[%d]: %s\n",j, argv[j]);
}
*/
pid_t id = fork();
if(id == 0){ //child:命令行解析
execvp(argv[0], argv); //执行进程程序替换,替换成功,则不再返回
exit(1); //替换失败,则程序退出
}
else if(id > 0){ //father:等待子进程退出
int status = 0;
pid_t ret = waitpid(id, &status, 0);
if(ret > 0){
printf("status code: %d\n", (status>>8)&0xff);
}
}
else{
perror("fork error!\n");
}
return 0;
}