进程的替换

exec 函数族, 是由六个 exec 函数组成的
        exec 函数族提供: 六种在进程中启动另一个程序的方法
        exec 函数族可根据 指定的文件名或目录名找到 可执行文件
        调用 exec 函数的进程并不创建新的进程, 故调用 exec 前后, 进程的进程号并不会改变, 其执行的程序完全由新的程序替换, 而新程序则从其 main 函数开始执行
     exec 函数族取代调用进程的数据段、 代码段和堆栈段

exec 函数族
 

#include <unistd.h>

int execl(const char *pathname,
          const char *arg0,...
          NULL);

int execlp(const char *filename,
           const char *arg0,...
           NULL);

int execle(const char *pathname,
           const char *arg0,..
           NULL,
           char *const envp[]);

int execv(const char *pathname,
          char *const argv[]);

int execve(const char *pathname,
           char *const argv[],
           char *const envp[])

     六个 exec 函数中只有 execve 是真正意义的系统调用(内核提供的接口), 其它函数都是在此基础上经过封装的库函数
  l(list):
          参数地址列表, 以空指针结尾。
     参数地址列表:
          char *arg0, char *arg1, ..., char *argn, NULL

v(vector):
         存有各参数地址的指针数组的地址
        使用时,先构造一个指针数组, 指针数组存各参数的地址, 然后将该指针数组地址作为函数的参数
p(path): 
       按 PATH 环境变量指定的目录搜索可执行文件
       以 p 结尾的 exec 函数取文件名做为参数

       当指定 filename 作为参数时, 若 filename 中包含/, 则将其视为路径名, 并直接到指定的路径中执行程序
e(environment):
      存有环境变量字符串地址的指针数组的地址

      execle 和 execve 改变的是 exec 启动的程序的环境变量( 新的环境变量完全由 environment 指定), 其他四个函数启动的程序则使用默认系统环境变量
注意:
       exec 函数族与一般的函数不同, exec 函数族中的函数执行成功后不会返回

       只有调用失败了, 它们才会返回- 1

      失败后从原程序的调用点接着往下执行

       在平时的编程中, 如果用到了 exec 函数族, 一定要记得加错误判断语句


getenv函数:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    printf("USER = %s\n",getenv("USER"));
    printf("GONGSI = %s\n",getenv("GONGSI"));
    return 0;
}

打印: 

#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    execl("/bin/ls","ls","-a","-l","-h",NULL);
        perror("execl");
    return 0;
}

打印:

 execlp函数:

#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    execlp("ls","ls","-a","-l","-h",NULL);
        perror("execlp");
    return 0;
}

打印:

 execv函数

#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    char *arg[] = {"ls", "-a", "-l", "-h", NULL};

    execv("/bin/ls",arg);
        perror("execv");
    return 0;
}

打印:

execvp函数: 

#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    char *arg[] = {"ls","-a","-l","-h",NULL};

    execvp("ls",arg);
        perror("execvp");
    return 0;
}

 打印:

execve函数:

#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    char *arg[]={"test", NULL};
    char *env[]={"USER=ME", "GONGSI=AIPU", NULL};

    execve("./test", arg, env);
        perror("execve");

    return 0;
}

一个进程调用 exec 后, 除了进程 ID, 进程还保留了下列特征不变:
        父进程号 , 进程组号 , 控制终端 , 根目录 , 当前工作目录 , 进程信号屏蔽集 , 未处理信号