最近我一直在学习系统编程课程,遇到了系统调用exec()和execve()。到目前为止,我无法找到这两者之间的任何区别,即使在维基百科上也没有明确的解释,那么exec()和execve()之间是否有区别呢?
请问有人能简要描述一下execl()、execv()、execle()、execvp()等exec家族系统调用吗?
最近我一直在学习系统编程课程,遇到了系统调用exec()和execve()。到目前为止,我无法找到这两者之间的任何区别,即使在维基百科上也没有明确的解释,那么exec()和execve()之间是否有区别呢?
请问有人能简要描述一下execl()、execv()、execle()、execvp()等exec家族系统调用吗?
系统调用中没有exec
,通常将所有execXX
调用作为一组引用。它们的本质相同:将一个新程序加载到当前进程中,并为其提供参数和环境变量。差异在于如何找到程序,如何指定参数以及环境从哪里来。
名称中带有v
的调用采用数组参数来指定新程序的argv[]
数组。末尾的参数由包含NULL
的数组元素指示。
名称中带有l
的调用将新程序的参数作为函数本身的可变长度参数列表接收。参数的结尾由(char *)NULL
参数指示。您应始终包括类型转换,因为NULL
可以是整数常量,而在调用可变参数函数时的默认参数转换不会将其转换为指针。
名称中带有e
的调用采用额外的参数(或在l
的情况下使用多个参数)来提供新程序的环境;否则,程序将继承当前进程的环境。这与argv
数组相同:对于execve()
,使用数组;对于execle()
,使用单独的参数。
名称中带有p
的调用将搜索PATH
环境变量以查找程序(如果它没有目录,即不包含/
字符)。否则,程序名称始终被视为可执行文件的路径。
FreeBSD 5.2添加了另一种变体:execvP
(大写P
)。这类似于execvp()
,但是它不是从PATH
环境变量获取搜索路径,而是显式地作为函数参数提供:
int execvP(const char *file, const char *search_path, char *const argv[]);
使用man exec
并阅读:
The execv(), execvp(), and execvpe() functions provide an array of pointers to
null-terminated strings that represent the argument list available to the new program.
The first argument, by convention, should point to the filename associated with the file
being executed. The array of pointers must be terminated by a NULL pointer.
execv
int execv(const char *path, char *const argv[]);
你可以将数组作为参数传递。
int execle(const char *path, const char *arg,
..., char * const envp[]);
几乎相同,但不是作为数组,而是作为值(字符串)列表,然后是指定环境的数组。
这里:
int execvp(const char *file, char *const argv[]);
您正在调用一个文件,没有路径,因此它期望您在调用之前已经处于正确的 路径
中。
最后但同样重要:
int execve(const char *filename, char *const argv[],
char *const envp[]);
与之前类似,但现在您有两个数组,用于参数和环境变量。
由于所有这些函数都属于 exec() 系列,让我根据附加字符将它们的含义进行区分:
1. execve():
p:不存在 => 将从 pathname
中获取要运行的程序的名称
v:存在 => 参数将作为 array
传递
e:存在 => 环境将从 envp argument
中获取
2. execle():
p:不存在 => 将从 pathname
中获取要运行的程序的名称
l:存在 => 参数将作为 list
传递
e:存在 => 环境将从 envp argument
中获取
3. execlp():
p:存在 => 将从指定的 filename
或系统将在 PATH
变量中搜索程序文件以获取要运行的程序的名称。
l:存在 => 参数将作为 list
传递
e:不存在 => 环境将从 caller's environ
中获取
4. execvp():
p:存在 => 将从指定的 filename
或系统将在 PATH
变量中搜索程序文件以获取要运行的程序的名称。
v:存在 => 参数将作为 array
传递
e:不存在 => 环境将从 caller's environ
中获取
5. execv():
p:不存在 => 将从 pathname
中获取要运行的程序的名称
v:存在 => 参数将作为 array
传递
e : not present => 环境变量将从调用者的环境变量
获取
6.execl():
p : not present => 要运行的程序名称将从路径名
中获取
l : present => 参数将作为列表
传递
e : not present => 环境变量将从调用者的环境变量
获取
exec()函数族用新的进程镜像替换现有进程镜像。这与fork()系统调用明显不同,后者会使得父进程和子进程在内存中共存。
int execv (const char *filename, char *const argv[])
文件名是新进程映像的文件。
argv是一个以空字符结尾的字符串数组。该数组的最后一个元素必须为null指针。
int execl (const char *filename, const char *arg0, …)
与execv相同,但参数以单个字符串(由逗号分隔)提供,而不是数组/向量。
int execve (const char *filename, char *const argv[], char *const env[])
int execle (const char *filename, const char *arg0, …, char *const env[])
int execvp (const char *filename, char *const argv[])
int execlp (const char *filename, const char *arg0, …)
这个功能和Excel函数相同,唯一不同的是它会像execvp函数一样执行文件名搜索。
在Linux系统中,如果您在Shell或终端上键入env
或printenv
,您将获得标准环境变量列表。
函数execl,execlp和execle需要将新程序的每个命令行参数作为单独的参数来指定。
对于execv、execvp和execve函数,我们必须构建一个指向参数的指针数组,并且该数组的地址是这三个函数的参数。
execve和execle函数允许我们传递指向环境字符串指针数组的指针。另外四个函数使用调用进程中的environ变量将现有环境复制到程序中。
p
表示该函数需要一个文件名参数,并使用PATH环境变量查找可执行文件。l
表示该函数需要一个参数列表,并且与字母v
互斥,后者表示它使用argv[]向量。字母e
表示该函数需要一个envp[]数组,而不是使用当前环境。
新程序从调用进程继承以下其他特性。
Process ID and the Parent Process ID
Real user ID and Real Group ID
Supplementary group IDs
Process group ID
Session ID
Controlling terminal
Time left until alarm clock
Current working directory
Root directory
File mode creation mask
File locks
Process signal mask
Pending signals
Resource limits
Values for tms_utime, tms_stime, tms_cutime, and tms_cstime.
在exec家族中,有一些函数在其功能和调用方式方面略有不同:
函数名称中包含字母p的函数(如execvp
和execlp
)接受一个程序名,并在当前执行路径中搜索该名称的程序;不包含字母p的函数必须提供要执行的程序的完整路径。
函数名称中包含字母v的函数(如execv
、execvp
和execve
)将新程序的参数列表作为以NULL结尾的字符串指针数组接受。函数名称中包含字母l的函数(如execl
、execlp
和execle
)使用C语言的varargs
机制接受参数列表。
函数名称中包含字母e的函数(如execve
和execle
)接受一个附加参数,即环境变量数组。该参数应为以NULL结尾的字符串指针数组,每个字符字符串都应为VARIABLE=value
形式。
exec*()
函数族,您可以在此处阅读:http://man7.org/linux/man-pages/man3/execl.3.html。 - alk