用fork函数创建子进程后,子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程完全由新程序代换,而新程序则从其 main函数开始执行。因为调用exec并不创建新进程,所以前后的进程ID并未改变。exec只是用另一个新程序替换了当前进程的正文、数据、堆和栈段。有六种不同的exec函数可供使用,它们常常被统称为exec函数。这些exec函数都是UNIX进程控制函数。用fork可以创建新进程,用exec可以执行新的程序。exit函数和两个wait函数处理终止和等待终止。这些是我们需要的基本的进程控制函数。
exec函数族的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件。这里的可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件,如果不是可以执行的文件,那么就解释成为一个shell文件
与一般情况不同,exec函数族的函数执行成功后不会返回,因为调用进程的实体,包括代码段,数据段和堆栈等都已经被新的内容取代,只留下进程ID等一些表面上的信息仍保持原样,颇有些神似"三十六计"中的"金蝉脱壳"。看上去还是旧的躯壳,却已经注入了新的灵魂。只有调用失败了,它们才会返回一个-1,从原程序的调用点接着往下执行。
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, 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 execvpe(const char *file, char *const argv[],char *const envp[]);
首先execl和execv开头的函数的区别是:execl开头的函数采用了我们更容易习惯的方式,把参数一个一个列出来,然后以一个NULL表示结束。execv开头的函数是以"char *argv[]"这样的形式传递命令行参数。
注:
- 命令行参数的第一个参数一般为程序名本身。最后一个参数为NULL;
- 当exec函数执行完毕后,便立即退出当前进程,不执行后面的语句,所以常常先fork一个子进程,然后调用exec函数。
- 其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。
不加:搜索路径名,要求参数path必须是一个完整的路径名
p:只赋一个文件名即可,函数会到环境变量PATH目录中寻找可执行文件。否则要求参数path必须是一个完整的路径名
e:函数传递指定参数envp,允许改变子进程的环境,无后缀e时,子进程使用当前程序的环境。envp也是一个以NULL结尾的字符串数组指针
返回值:出错返回-1,成功不返回值。
system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。
int system(const char * string);
如果exec()失败,表示不能执行Shell,返回值相当于Shell执行了exit(127)功能:执行shell命令参数:string:要执行的shell命令返回值:如果fork()失败 返回-1:出现错误
如果执行成功则返回子Shell的终止状态如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-1。若参数string为空指针(NULL),则返回非零值>;。如果system()调用成功则最后会返回执行shell命令后的返回值,但是此返回值也有可能为 system()调用/bin/sh失败所返回的127,因此最好能再检查errno 来确认执行成功。