exec
用fork函数创建新的子进程后,子进程往往要调用一种exec函数以执行另一个程序,当进程调用一种exec函数时,该进程执行的程序完全替换为新程序,而新程序则从其main函数开始执行。因为调用exec并不创建新进程,所以前后的进程ID并未改变。exec只是用磁盘上的一个新程序替换了当前进程的正文短、数据段、堆段和栈段。
有7中不同的exec函数可供使用,它们常常被统称为exec函数,我们可以使用这7个函数中的任一个。这些exec函数使得UNIX系统进程控制原语更加完善。用fork可以创建新进程,用exec可以初始执行新的程序。exit函数和wait函数处理终止和等待终止。这些是我们需要的基本的进程控制原语。
|
|
这些函数之间的第一个区别是前4个函数去路径名作为参数,后两个函数则取文件名作为参数,最后一个取文件描述符作为参数。当指定filename作为参数时:
- 如果filename中包含/,则就将其视为路径名。
- 否则就按PATH环境变量,在它所指定的各目录中搜寻可执行文件。
PATH变量包含了一张目录表(称为路径前缀),目录之间用冒号(:)分隔。
查看PATH环境变量:
|
|
如果execlp或者execvp使用路径前缀中的一个找到了一个可执行文件,但是该文件不是由连接编辑器长生的机器可执行文件,则就认为该文件是一个shell脚本,于是试着调用/bin/sh,并以该filename作为shell的输入。
第二个区别与参数表的传递有关(l表示list,v表示矢量vector)。函数execl、execlp和execle要求将新程序的每个命令行参数都说明为一个单独的参数,这种参数以空指针结尾((char*)0)。对于另外4个函数(execv、execvp、execve和fexecve),则应先构造一个指向各参数的指针数组,然后将该数组地址作为这4个函数的参数。
最后一个区别与向新程序传递的环境表相关。以e结尾的3个函数(execle、execve和fexecve)可以传递一个指向环境字符串指针数组的指针。其他4个函数则使用调用进程中的environ变量为新程序复制现有环境。
这7个exec函数的参数很难记忆。函数名中的字符串会给我们一些帮助。字母p表示该函数取filename作为参数,并且用PATH环境变量寻找可执行文件。字母l表示该函数取一个参数表,它与字母v互斥。v表示该函数取一个argv[]矢量。最后,字母e表示该函数取envp[]数组,而不使用当前环境。下图显式了这7个函数之间的区别。
在很多UNIX实现中,这7个函数中只有execve时内核的系统调用。另外6个只是库函数,他们最终都要调用该系统调用。这7个函数之间的关系如下:
在这种安排下,库函数execlp和execvp使用PATH环境变量,查找查找第一个包含名为filename的可执行文件的路径名前缀。fexecve库函数使用/proc把文件描述符参数转换成路径名,execve用该路径名去执行程序。
示例
演示execle和execlp的用法
exec.c
|
|
程序要执行两次的echoall程序如下echoall.c所示。这是一个很普通的程序,它回显所有命令行参数及全部环境表。
注意:
- 我们将第一个参数(新程序中的argv[0])设置为路径名的文件名分量(”echoall.o”)。某些shell将此参数设置为完全的路径名。这只是一个惯例。我们可将argv[0]设置为任何字符串。当login命令执行shell时就是这样做的。在执行shell之前,login在argv[0]之前加一个/作为前缀,这向shell指明它是作为登录shell被调用的。登录shell将执行启动配置文件(start-up profile)命令,而非登录shell则不会执行这些命令。
- execle要求路径名和一个特定的环境。而execlp,它用一个文件名,所以其PATH环境变量所指向的各目录中搜寻可执行文件,我们的echoall.o在/home/vrlive/bin也有一份。
|
|
echoall.c
|
|
|
|