Linux学习笔记:进程程序替换

进程替换原理

用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序

exec函数

exec 函数的作用

当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变

当调用了exec函数进行进程的替换的时候,若父子进程有共享的数据,那么子进程会发生写时拷贝,因此子进程的替换不会影响父进程

使用exec函数时需要用到头文件:
#include<unistd.h>

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[]);

参数理解

  1. int execl(const char *path, const char *arg, …): 这个函数接受一个程序路径 的环境变量path,需要把环境变量的路径进行传参,然后是一系列的参数,以NULL结尾。这些参数会传递给要执行的程序。注意,每个参数都需要作为一个单独的字符串传递,并以NULL结尾
    举例:
execl("/usr/bin/bash", "bash","test.sh", NULL);

这里调用的第一个参数需要指明路径

  1. int execlp(const char *file, const char *arg, …): 与execl不同的是,但是它会在系统的 PATH 环境变量指定的目录中搜索可执行文件。其他方面与 execl 类似。
    举例:
execlp("bash","bash","test.sh",NULL);
  1. int execle(const char *path, const char *arg, …,char *const envp[]): 这个函数接受一个程序路径 path,然后是一系列的参数,以NULL结尾,最后是一个环境变量数组 envp[]。通过传递 envp 参数,可以控制要执行的程序所使用的环境变量,这对于一些需要特定环境配置的程序是非常有用的。
    举例:
//这里的环境变量需要自己组建并通过envp传参
execle("ps", "ps", "-ef", NULL, envp);
  1. int execv(const char *path, char *const argv[]): 这个函数与 execl 类似,但是参数以数组的形式传递,即参数数组 argv[] 包含了要传递给程序的参数,以NULL结尾。因此在使用此函数时需要提前定义argv[]数组
    举例:
execv("/bin/ps", argv);
  1. int execvp(const char *file, char *const argv[]): 类似于 execv,但不需要传入完整画背景变量的路径,是它会在系统的 PATH 环境变量指定的目录中搜索可执行文件,相同点是需要利用argv[]数组进行传参
execvp("ls", argv);
  1. int execve(const char *path, char *const argv[], char *const envp[]): 这个函数与 execle 类似,但是参数以数组的形式传递,即参数数组 argv[] 包含了要传递给程序的参数,最后是一个环境变量数组 envp[],用于显式地传递环境变量给要执行的程序。,需要自己组装环境变量
execve("/bin/ps", argv, envp);

exec系列函数命名理解

  • l(list) : 表示参数采用列表
  • v(vector) : 参数用数组
  • p(path) : 有p自动搜索环境变量PATH
  • e(env) : 表示自己维护环境变量

程序替换函数exec函数的使用样例

下面我会分别展示如何在C语言中使用这几种exec系列的函数。这些函数主要用于在当前进程中创建子进程,并让子进程执行一个新的程序,父进程等待子进程.
各个函数之间的区别主要在于如何指定要执行的程序和参数,以及环境变量。

每个例子都展示了如何使用子进程来调用不同的exec函数来执行ls命令,并列出当前目录下的文件。如果exec函数调用成功,当前进程会被新程序替换,exec函数调用后子进程的代码不会被执行。因此,如果看到了perror的输出,那么就意味着调用失败了。

1. 使用execl函数

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h> // 为了使用wait()

int main() {
    pid_t pid = fork();

    if (pid == 0) { // 子进程
        printf("Child process running ls with execl\n");
        execl("/bin/ls", "ls", "-l", (char *)NULL);
        perror("execl failed");
    } else if (pid > 0) { // 父进程
        wait(NULL); // 等待子进程完成
        printf("Child process finished\n");
    } else { // fork失败
        perror("fork failed");
    }
    return 0;
}

2. 使用execlp函数

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
    pid_t pid = fork();

    if (pid == 0) {
        printf("Child process running ls with execlp\n");
        execlp("ls", "ls", "-l", (char *)NULL);
        perror("execlp failed");
    } else if (pid > 0) {
        wait(NULL);
        printf("Child process finished\n");
    } else {
        perror("fork failed");
    }
    return 0;
}

3. 使用execle函数

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
    pid_t pid = fork();
    char *envp[] = { "PATH=/bin", NULL };

    if (pid == 0) {
        printf("Child process running ls with execle\n");
        execle("/bin/ls", "ls", "-l", (char *)NULL, envp);
        perror("execle failed");
    } else if (pid > 0) {
        wait(NULL);
        printf("Child process finished\n");
    } else {
        perror("fork failed");
    }
    return 0;
}

4. 使用execv函数

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
    pid_t pid = fork();
    char *argv[] = { "ls", "-l", NULL };

    if (pid == 0) {
        printf("Child process running ls with execv\n");
        execv("/bin/ls", argv);
        perror("execv failed");
    } else if (pid > 0) {
        wait(NULL);
        printf("Child process finished\n");
    } else {
        perror("fork failed");
    }
    return 0;
}

5. 使用execvp函数

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
    pid_t pid = fork();
    char *argv[] = { "ls", "-l", NULL };

    if (pid == 0) {
        printf("Child process running ls with execvp\n");
        execvp("ls", argv);
        perror("execvp failed");
    } else if (pid > 0) {
        wait(NULL);
        printf("Child process finished\n");
    } else {
        perror("fork failed");
    }
    return 0;
}

6. 使用execve函数


#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
    pid_t pid = fork();
    char *envp[] = { "PATH=/bin", NULL };

    if (pid == 0) {
        printf("Child process running ls with execle\n");
        execve("/bin/ls", argv, envp);
        perror("execle failed");
    } else if (pid > 0) {
        wait(NULL);
        printf("Child process finished\n");
    } else {
        perror("fork failed");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值