exec函数族是把当前进程映像替换成新的程序文件
exec
函数族会根据指定的文件名或目录名查询可执行文件,找到后会使用它去取代原调用进程的数据段、代码段、堆栈段。在执行完毕后,原调用进程的内容除进程号
pid
外全部被新的进程所替换。另外,这里的可执行文件可以是二进制文件,也可以是Linux系统下任何可执行的脚本程序。
实际上,Linux中并没有
exec
函数,而是有6个以
exec
开头的函数组成
exec
函数族。
#include <unistd.h>
int execl(const char *path, const char *arg, ...)
int execlp(const char *path, 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[])
简单来说,exec
函数族都是以exec
开头,后面跟的不同字母表示不同的涵义:
l
表示 list
,指代的是命令行参数列表。
p
表示 path
,指定搜索文件file
时所使用的path
变量。
v
表示vector
,指代的是命令行参数数组。
e
表示 environment
,指代的是环境变量数组。
path
表示要执行的程序路径,可以是绝对路径或是相对路径。
file
表示要执行的程序名称,如果该参数中包含/
字符则视为路径名并直接执行,否则则视为单独的文件名,系统将会根据环境变量PATH
中设置的路径顺序去搜索指定的文件。
argv
表示命令行参数的矢量数组
envp
表示带有该参数的exec
函数可以在调用时指定一个环境变量数组,其他不带该参数的exec
函数则使用调用进程的环境变量。
arg
表示程序的第0个参数,也就是程序名本身,相当于argv[0]
。
...
表示命令行参数列表,调用相应程序时有多少个命令行参数就需要有多少个输入参数项。
函数执行成功不会返回,若执行失败则返回-1,失败原因会记录在error
中。
事实上,这6个函数中真正的系统调用只有execve
函数,其它5个都是库函数,它们最终都会调用execve
这个系统调用。
int execl(const char *path, const char *arg, ...);
execl
中的l
表示list
即命令行参数列表,它的功能是通过“路径+文件名”的方式来加载一个进程,参数path
字符指针指向要执行的文件路径,参数arg
表示文件名称,参数...
表示可变参数,可变参数必须使用NULL
结尾。
exec("/bin/ls", "ls", "-a", "-l", NULL)
$ vim execl.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
printf("parent process begin\n");
pid_t pid = vfork();
if(pid == -1)
perror("vfork fail");
exit(1);
else if(pid == 0)
printf("child process begin\n");
if(execl("/bin/ls", "ls", "-l", NULL) == -1)
perror("execl fail");
_exit(1);
sleep(1);
printf("parent process end\n");
return 0;
$ gcc -o execl.out execl.c
$ ./execl.out
parent process begin
child process begin
总用量 16
-rw-r--r-- 1 jc jc 400 3月 6 00:32 execl.c
-rwxr-xr-x 1 jc jc 8544 3月 6 00:33 execl.out
parent process end
注意:vfork
函数所创建的子进程里直接调用exec
函数,则立即启动另一个进程取代其自身,这比调用fork
函数完成同样的工作要快的多。
execl("/bin/ls", "ls", "-l", NULL) == -1
execl("/bin/ls", "ls", "-l", (char *)0) == -1
这两种写法中如果使用常量0来表示一个空指针,则必须将它强制转换为一个字符指针,否则它将解释为整形参数。如果一个整形参数的长度与char *
的长度不同,那么exec
函数的实际参数将会出错。如果函数调用成功,进程自己的执行代码会变成加载程序的代码,execl()
后面的代码也就不会再执行。