拂拉氏头像
关注
【知识讲解】 Linux程序替换相关接口讲解封面图

【知识讲解】 Linux程序替换相关接口讲解


目录

前言

Part1. exec介绍

Part2. exec 系列函数分类

Part3. execl

Part4. execlp

Part5. execv

Part6. execvp

Part7. execle

Part8. execve

Part9. exec相关补充

Part10. 结语


前言

   Linux系统中,我们可以进行程序的替换,对于他的理解是非常重要的,接下来来跟随小编的视角来看看吧。


let's go!!!!!!!!


Part1. exec介绍

在 Linux 中,fork() 只能创建一个和父进程代码相同的子进程。如果想让子进程去运行另一个全新的程序,就需要使用 exec 系列函数。


exec 的作用不是创建新进程,而是:
把当前进程的代码段、数据段、堆、栈替换成新程序,让这个进程转而运行另一个程序。


所以:

• fork():创建新进程

• exec():替换进程运行的程序

Linux 中运行一个新程序,通常是:
fork() + exec()
先复制出一个子进程,再让子进程执行别的程序。


Part2. exec 系列函数分类

#include <unistd.h>
exec 不是一个单一函数,而是一组函数:
execl
execlp
execle
execv
execvp
execve


它们的区别可以按三个维度记忆:
维度 含义 
l 以可变参数列表传递命令行参数 
v 以字符串数组传递命令行参数 
p 自动在 PATH 环境变量中查找程序 
e 可以传入自定义环境变量 


Part3. execl

int execl(const char* path, const char* arg, ...);
参数说明

• path:程序的完整路径

• arg:第一个参数,通常是程序名本身

• ...:后续参数,构成命令行参数列表

• 最后必须以 NULL 结尾


示例
execl("/usr/bin/ls", "ls", "-l", "-a", NULL);
对应命令:
ls -l -a
注意点

1. 第一个参数是完整路径:/usr/bin/ls

2. 第二个参数是 argv[0],一般写程序名:"ls"

3. 参数依次往后传

4. 最后必须传 (char*)NULL

5. const char* 传 NULL 时建议强转:(char*)NULL


Part4. execlp

int execlp(const char* file, const char* arg, ...);


execlp 和 execl 的区别是:
函数 是否自动搜索 PATH 
execl 否,必须写完整路径 
execlp 是,可以直接写程序名 


示例
execlp("ls", "ls", "-l", NULL);
系统会在环境变量 PATH 指定的目录中查找 ls,比如:
/usr/bin/ls
/bin/ls
所以 execlp("ls", ...) 能运行,而 execl("ls", ...) 通常会失败。


Part5. execv

int execv(const char* path, char* const argv[]);


execv 不使用可变参数列表,而是把参数放到一个字符串数组里。

示例
char* argv[] = {"ls", "-l", "-a", NULL};
execv("/usr/bin/ls", argv);
等价于:
ls -l -a
适合参数数量动态变化的场景。


Part6. execvp

int execvp(const char* file, char* const argv[]);


execvp = execv + p

也就是:

• 用数组传参

• 自动搜索 PATH

示例
char* argv[] = {"ls", "-l", NULL};
execvp("ls", argv);


Part7. execle

int execle(const char* path, const char* arg, ..., char* const envp[]);


execle 可以给新程序传入自定义环境变量。

示例
char* envp[] = {"HOME=/root", "PATH=/usr/bin", NULL};
execle("/usr/bin/ls", "ls", "-l", NULL, envp);
新程序运行时,就能拿到这些环境变量。


Part8. execve

int execve(const char* path, char* const argv[], char* const envp[]);


execve 是真正的系统调用,其他 exec 函数通常在底层调用 execve。


参数 说明 
path 程序完整路径 
argv 命令行参数数组 
envp 环境变量数组 


Part9. exec相关补充

如果 exec 成功,当前进程的代码已经被替换,原来的代码不会继续执行。
exec 成功,不返回。
失败时

只有 exec 失败时,才会返回 -1,并设置 errno。


execl("/usr/bin/ls", "ls", "-l", NULL);
perror("execl failed");


常见失败原因:

• 文件不存在

• 没有执行权限

• 路径错误

• 参数格式错误

• 内存不足


为什么最后要加 NULL
execl("/usr/bin/ls", "ls", "-l", "-a", NULL);


NULL 的作用是:
标记参数列表结束。因为 execl 是可变参数函数,编译器不知道参数有多少个,必须用 NULL 告诉它参数结束了。


exec 和 fork 的配合
 

pid_t pid = fork();

if (pid == 0) {
    // 子进程
    execl("/usr/bin/ls", "ls", "-l", NULL);
    perror("execl");
    exit(1);
} else if (pid > 0) {
    // 父进程
    wait(NULL);
}

执行流程:

1. fork() 创建子进程

2. 子进程调用 execl()

3. 子进程的代码被替换成 ls

4. ls 开始运行

5. 父进程 wait() 回收子进程


exec 前后进程身份不变

调用 exec 后,虽然程序换了,但:

• PID 不变

• PPID 不变

• 用户 ID 不变

• 进程组不变

• 大部分文件描述符继续有效

所以 exec 不是“创建新进程”,而是“同一个进程运行新程序”。


exec 常用示例

示例 1:运行 ls
execl("/usr/bin/ls", "ls", "-l", NULL);


示例 2:运行 pwd
execlp("pwd", "pwd", NULL);


示例 3:运行 echo
execlp("echo", "echo", "hello", "world", NULL);


示例 4:运行自定义程序
execl("./a.out", "a.out", NULL)


Part10. 结语

  这篇文章我们认识并知道了Linux程序替换,接下来,小编还会带来更多Linux相关的知识,敬请期待~

 最后,祝大家可以:春风得意马蹄疾,一日看尽长安花!

 最后的最后,要是觉得本文还可以的话,可以点点赞,关注小编一波,谢谢大家!~

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2501_93971468/article/details/165236492

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--