Linux下的程序替换, exec函数族,以及利用程序替换实现一个简单的minishell

程序替换

程序替换是指替换一个正在运行中的程序.
我们知道, linux中进程就是一个pcb, 是对一个运行中程序的描述, 通过虚拟地址空间及页表, 将程序运行对应的数据及代码映射到物理内存, 程序替换就是pcb不变, 但是映射到物理内存的代码和数据改变成另一个程序.

那么, 如何去理解程序替换呢?
我们可以这样去思考, 当我们使用 fork()创建子进程之后, 子进程执行的是和父进程相同的程序(先不考虑根据返回值进行代码分流), 这个时候, 我们就可以在子进程当中调用exec函数来执行其他的程序, 如果这个程序出了问题奔溃掉也不会影响父进程, 没有问题则帮助我们完成其他的任务.

exec函数族相关函数介绍

execl(char* path, char* arg, ...);
execv(char* path, char* argv[]);

execlp(char* filename, char* arg, ...);
execvp(char* filename, char* argv[]);

execle(char* path, char* arg, ..., char* env[]);
execve(char* filename, char* argv[], char* env[]);
//这些函数运行成功的时候是没有返回值的, 因为跑去运行其它程序了
//若有返回值的话, 只能是程序替换失败, 返回-1

关于exec函数族的理解

  1. l和v的区别
    新程序的运行参数赋予方式不同

     //程序替换运行 ls -l, 直接将新程序运行所需要的参数以不定参的形式传入, 并以NULL作为结束
     execl("/bin/ls", "ls", "-l", NULL);
     
     //程序替换运行 ls -l, 将新程序运行所需要的参数通过字符串指针数组的形式传入, 数组中依然以NULL作为结束表示
     char* argv[] = {"ls", "l", "NULL"}
     execv("/bin/ls", argv);
    
  2. 有没有p的区别
    新程序的名称是否需要带路径

     //带p不需要指定路径
     execlp("ls", "ls", "-l", NULL);
     
     char* argv[] = {"ls", "l", "NULL"}
     execvp("ls", argv);
     //注意, 带p虽然可以不用指定路径, 但是程序必须在PATH环境变量指定的路径下
    
  3. 有没有e的区别
    新运行的程序是否需要重新自定义环境变量, 带e的自定义环境变量, 不带e使用当前进程默认的环境变量

     //自己定义的环境变量
     char *env[3] = {NULL};
     env[0] = "MYVAL=1000";
     env[1] = NULL;
    
     execle("ls", "ls", "-l", NULL);
     
     char* argv[] = {"ls", "l", "NULL", env}
     execve("ls", argv, env);
    

利用程序替换实现一个简单的minishell

#include 
#include 
#include 
#include 

int main()
{
    while(1) {
        //增加一个类似于shell的提示
        printf("[MineMinishell]$ ");
        fflush(stdout);//刷新标准输出缓冲区,不用等到程序结束才打印提示
        
        //等待标准输入
        char buf[1024] = {0};
        fgets(buf, 1023, stdin);
        buf[strlen(buf)-1] = '\0'; //注意这里是把最后接收到的换行符置为'\0'
       
        char *argv[32] = {NULL};
        int argc = 0;
        char *ptr = buf;
        
        //对接收到的命令字符串进行解析
        while(*ptr != '\0') {
            if (*ptr != ' ') {
                argv[argc] = ptr;
                argc++;
                while(*ptr != ' ' && *ptr != '\0') {
                    ptr++;               
                }
                *ptr = '\0';
            }
            ptr++;
        }
        argv[argc] = NULL;//最后一个参数的下一个位置置NULL
        
        //创建子进程
        pid_t pid = fork();
        if (pid == 0) {
        	//在子进程中程序替换
            execvp(argv[0], (char**)argv);//程序替换成功就去运行新程序
            perror("execvp error");//运行到这一步表示程序替换失败了
            exit(0);
        }
        wait(NULL);//进程等待,等待子进程退出,回收子进程资源
    }
    return 0;
}

你可能感兴趣的:(linux)