1. 基本概念
1.1 进程替换 vs. 进程创建
- 进程创建:使用
fork()
或clone()
等系统调用创建一个新的子进程,子进程是父进程的副本,拥有相同的代码和数据。 - 进程替换:使用
exec
系列函数在当前进程中加载并执行一个新的程序,替换掉当前进程的映像,但保留PID、文件描述符等资源。
1.2 exec
系列函数
exec
系列函数用于在当前进程中执行一个新程序。常见的exec
函数包括:
这些函数的命名规则如下:
- 前缀:
exec
- 中间部分:
l
(list):参数以列表形式传递。v
(vector):参数以数组形式传递。
- 后缀:
e
:允许传递环境变量。p
:使用PATH
环境变量来查找可执行文件。
2. 常用的exec
函数
2.1 execl()
函数原型:
#include <unistd.h>
int execl(const char *path, const char *arg, ... /* (char *) NULL */);
参数:
path
:要执行的可执行文件的路径。arg
:第一个参数,通常是程序名。...
:可变参数列表,以NULL
结尾。
例子:
#include <stdio.h>
#include <unistd.h>
int main() {
printf("Before execl\n");
execl("/bin/ls", "ls", "-l", NULL);
// 如果execl成功,以下代码不会执行
perror("execl failed");
return 1;
}
2.2 execv()
函数原型:
#include <unistd.h>
int execv(const char *path, char *const argv[]);
参数:
path
:要执行的可执行文件的路径。argv
:参数数组,以NULL
结尾。
例子:
#include <stdio.h>
#include <unistd.h>
int main() {
char *args[] = { "ls", "-l", NULL };
printf("Before execv\n");
execv("/bin/ls", args);
// 如果execv成功,以下代码不会执行
perror("execv failed");
return 1;
}
2.3 execlp()
函数原型:
#include <unistd.h>
int execlp(const char *file, const char *arg, ... /* (char *) NULL */);
参数:
file
:可执行文件名,会在PATH
环境变量中查找。arg
:第一个参数,通常是程序名。...
:可变参数列表,以NULL
结尾。
例子:
#include <stdio.h>
#include <unistd.h>
int main() {
printf("Before execlp\n");
execlp("ls", "ls", "-l", NULL);
// 如果execlp成功,以下代码不会执行
perror("execlp failed");
return 1;
}
2.4 execvp()
函数原型:
#include <unistd.h>
int execvp(const char *file, char *const argv[]);
参数:
file
:可执行文件名,会在PATH
环境变量中查找。argv
:参数数组,以NULL
结尾。
例子:
#include <stdio.h>
#include <unistd.h>
int main() {
char *args[] = { "ls", "-l", NULL };
printf("Before execvp\n");
execvp("ls", args);
// 如果execvp成功,以下代码不会执行
perror("execvp failed");
return 1;
}
2.5 execle()
函数原型:
#include <unistd.h>
int execle(const char *path, const char *arg, ... /* (char *) NULL, char * const envp[] */);
参数:
path
:要执行的可执行文件的路径。arg
:第一个参数,通常是程序名。...
:可变参数列表,以NULL
结尾。envp
:环境变量数组。
例子:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
char *env[] = { "PATH=/bin", NULL };
printf("Before execle\n");
execle("/bin/ls", "ls", "-l", NULL, env);
// 如果execle成功,以下代码不会执行
perror("execle failed");
return 1;
}
2.6 execvpe()
#include <unistd.h>
int execvpe(const char *file, char *const argv[], char *const envp[]);
参数
file
:要执行的可执行文件的名称。如果file
中包含斜杠 (/
),则将其视为路径名,直接尝试执行。(如果file
不包含斜杠,则会在PATH
环境变量指定的目录中查找可执行文件。)argv
:参数数组,以NULL
结尾。argv[0]
通常是程序名。envp
:环境变量数组,以NULL
结尾。每个环境变量以"NAME=VALUE"
的形式表示。
例子:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
// 要执行的程序及其参数
char *args[] = { "printenv", "MY_VAR", NULL };
// 自定义环境变量
char *env[] = { "MY_VAR=HelloWorld", "PATH=/bin:/usr/bin", NULL };
printf("Before execvpe\n");
// 执行程序
if(execvpe("printenv", args, env) == -1) {
perror("execvpe failed");
exit(1);
}
// 如果 execvpe 成功,以下代码不会执行
return 0;
}
2.7 execve()(这个上面查库没有,要单独查)
函数原型:
参数:
pathname
:要执行的可执行文件的路径。argv
:参数数组,以NULL
结尾。envp
:环境变量数组。
例子:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
char *args[] = { "ls", "-l", NULL };
char *env[] = { "PATH=/bin", NULL };
printf("Before execve\n");
execve("/bin/ls", args, env);
// 如果execve成功,以下代码不会执行
perror("execve failed");
return 1;
}
3. 错误处理
大多数exec
函数在成功时不会返回,如果失败则返回-1,并设置errno
变量。常见的错误包括:
- ENOENT:文件不存在。
- EACCES:权限不足。
- ENOEXEC:可执行文件格式错误。
例子:
#include <stdio.h>
#include <unistd.h>
int main() {
if(execl("/bin/ls", "ls", "-l", NULL) == -1) {
perror("execl failed");
}
// 如果execl成功,以下代码不会执行
return 1;
}