(根据参考文档翻译整理而成,针对原文有补充)
exec函数家族用新进程替换当前正在运行的进程。它可以通过使用另一个C程序来运行一个C程序,它位于头文件unistd.h下。 exec系列中有许多成员,下面以示例显示。
execvp
execvp:使用此命令,创建的子进程不必与父进程运行相同的程序。exec类型的系统调用允许进程运行任何程序文件,其中包括二进制可执行文件或shell脚本。语法:
int execvp (const char *file, char *const argv[]);
file:表示被执行的文件的文件名
argv:是以null结尾的字符指针数组。argv参数描述了一个或多个指向以null结尾的字符串的指针列表,这些字符串作为参数列表传递给file文件进行执行。
示例1
让我们看一个小例子,展示如何在C中使用 execvp() 函数。我们将有两个.C文件,EXEC.c和execDemo.c,并通过调用execDemo.c中的 execvp() 函数,将执行execDemo.c替换为执行EXEC.c。
//EXEC.c
#include<stdio.h>
#include<unistd.h>
int main()
{
int i;
printf("I am EXEC.c called by execvp() ");
printf("\n");
return 0;
}
使用命令创建EXEC.c的可执行文件
gcc EXEC.c -o EXEC
//execDemo.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
//A null terminated array of character
//pointers
char *args[]={"./EXEC",NULL};
execvp(args[0],args);
/*All statements are ignored after execvp() call as this whole
process(execDemo.c) is replaced by another process (EXEC.c)
*/
printf("Ending-----");
return 0;
}
使用命令创建execDemo.c的可执行文件:
gcc execDemo.c -o execDemo
使用命令./excDemo运行execDemo.c的可执行文件后,我们得到以下输出:
I AM EXEC.c called by execvp()
编译文件execDemo.c时,一旦执行execvp(args[0],args) 语句,该程序就会被程序EXEC.c取代。之所以不会打印“ Ending-–”,是因为一旦调用 execvp() 函数,该程序就会被程序EXEC.c取代。
示例2
execvp执行shell的示例,d.sh内容为:
#!/bin/bash
date
test.c与d.sh在同一目录下,内容为:
#include <stdio.h>
int main()
{
char *arglist[]={"sh","d.sh",NULL};
printf("begin\n");
execvp("sh",arglist);
printf("end\n");
}
编译并执行,因为execvp执行d.sh后就结束了,所以并不会打印"end"。
# gcc test.c -o test
# ./test
begin
Mon Feb 15 22:30:17 CST 2021
execv
execv:就语法而言,与 execvp() 函数非常相似。
语法:
int execv(const char *path, char *const argv[]);
path:指向正在被执行文件的路径
argv[]:是以null结尾的字符指针数组
示例3
让我们看一个小例子来说明如何在C中使用 execv() 函数。这个例子类似于上面显示的 execvp() 的例子。
//EXEC.c
#include<stdio.h>
#include<unistd.h>
int main()
{
int i;
printf("I am EXEC.c called by execv() ");
printf("\n");
return 0;
}
使用命令创建EXEC.c的可执行文件:
gcc EXEC.c -o EXEC
//execDemo.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
//A null terminated array of character
//pointers
char *args[]={"./EXEC",NULL};
execv(args[0],args);
/*All statements are ignored after execvp() call as this whole
process(execDemo.c) is replaced by another process (EXEC.c)
*/
printf("Ending-----");
return 0;
}
使用命令创建execDemo.c的可执行文件
gcc execDemo.c -o execDemo
使用命令./excDemo运行execDemo.c的可执行文件后,我们得到以下输出:
I AM EXEC.c called by execv()
execvp和execv的区别,是第一个参数的不同,一个是file,一个是path,如果将示例2修改为execv的程序,test.c代码如下:
示例4
#include <stdio.h>
int main()
{
char *arglist[]={"sh","d.sh",NULL};
printf("begin\n");
execv("/bin/bash",arglist);
printf("end\n");
}
execlp和execl
execlp 和 execl:这两个也有相同的用途,但是它们的语法略有不同。
int execlp(const char *file, const char *arg,.../* (char *) NULL */);
int execl(const char *path, const char *arg,.../* (char *) NULL */);
file:正在执行的文件的文件名
const char *arg和省略号:描述一个或多个指向以null终止的字符串的指针的列表,这些字符串表示可用于执行的程序的参数列表。
上面的相似的C程序可以用 execlp() 或 execl() 函数执行,它们将执行相同的任务,即用新进程替换当前进程。
示例5
将示例2中的test.c改成execl的程序为:
#include <stdio.h>
int main()
{
char *arglist[]={"sh","d.sh",NULL};
printf("begin\n");
execl("/bin/bash",arglist[0], arglist[1], arglist[2]);
printf("end\n");
}
execvpe和execle
execvpe 和 execle:这两个函数也有相同的用途,但是它们的语法与上面提到的exec家族的所有成员都有点不同。
int execvpe(const char *file, char *const argv[],char *const envp[]);
int execle(const char *path, const char *arg, .../*, (char *) NULL,
char * const envp[] */);
上面显示的语法与所有上面的exec成员都有一个不同的参数:
char * const envp[]:允许调用者通过参数envp指定执行程序的环境。
envp:此参数指向以null结尾的字符串的指针数组,必须由null指针结尾。其他函数从调用进程中的外部变量environ获取新进程映像的环境。
参考文档
[1]MAZHAR IMAM KHAN.exec family of functions in C[EB/OL].https://www.geeksforgeeks.org/exec-family-of-functions-in-c/,2019-05-24.