我们用fork函数创建新进程后,经常会在新进程中调用exec函数去执行另外一个程序。当进程调用exec函数时,该进程被完全替换为新程序。因为调用exec函数并不创建新进程,所以前后进程的ID并没有改变。
功能:
在调用进程内部执行一个可执行文件。可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件。
函数族:
exec函数族分别是:execl, execlp, execle, execv, execvp, execvpe
函数原型:
#include
extern char **environ;
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[]);
返回值:
exec函数族的函数执行成功后不会返回,调用失败时,会设置errno并返回-1,然后从原程序的调用点接着往下执行。
参数说明:
path:可执行文件的路径名字
arg:可执行程序所带的参数,第一个参数为可执行文件名字,没有带路径且arg必须以NULL结束
file:如果参数file中包含/,则就将其视为路径名,否则就按 PATH环境变量,在它所指定的各目录中搜寻可执行文件。
exec族函数参数极难记忆和分辨,函数名中的字符会给我们一些帮助:
l : 使用参数列表
p:使用文件名,并从PATH环境进行寻找可执行文件
v:应先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数的参数。
e:多了envp[]数组,使用新的环境变量代替调用进程的环境变量
文件echoarg.c
#include
int main(int argc,char *argv[])
{
int i;
for(i=0;i<argc;i++)
{
printf("argv[%d]:%s\n",i,argv[i]);
}
return 0;
}
文件 a.c
#include
#include
#include
//函数原型:int execl(const char *path, const char *arg, ...);
int main(void)
{
printf("before execl\n");
//如果execl执行成功,下列代码就不会执行
if(execl("./bin/echoarg","echoarg","abc",NULL) == -1) //如果excel等于-1,执行失败,下面的代码就执行
{
printf("execl failed!\n");
perror("Why"); //打印错误
}
printf("after execl\n"); //execl执行成功则不打印这句话
return 0;
}
运行结果:在当前目录下找不到文件的位置
文件b.c 与a.c的区别:
#include
#include
#include
//函数原型:int execl(const char *path, const char *arg, ...);
int main(void)
{
printf("before execl\n");
//如果execl执行成功,下列代码就不会执行
if(execl("./echoarg","echoarg","abc",NULL) == -1) //如果excel等于-1,执行失败,下面的代码就执行
{
printf("execl failed!\n");
perror("Why"); //打印错误
}
printf("after execl\n"); //execl执行成功则不打印这句话
return 0;
}
如果参数file中包含/,则就将其视为路径名,否则就按 PATH环境变量,在它所指定的各目录中搜寻可执行文件。举个例子,PATH=/bin:/usr/bin
#include
#include
#include
//函数原型:int execlp(const char *file, const char *arg, ...);
int main(void)
{
printf("before execl\n");
//如果execlp执行成功,下列代码就不会执行
if(execlp("ps","ps",NULL,NULL) == -1) //如果excel等于-1,执行失败,下面的代码就执行
{
printf("execl failed!\n");
perror("Why"); //打印错误
}
printf("after execl\n"); //execl执行成功则不打印这句话
return 0;
}
结果:
总结:从上面的实验结果可以看出,上面的exaclp函数带p,所以能通过环境变量PATH查找到可执行文件ps
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4
5 int main(void)
6 {
7 printf("before execl\n");
8
9 char *argv[] = {"ps",NULL,NULL};
10 if(execv("/bin/ps",argv) == -1) //需要添加路径来找到执行文件
11 {
12 printf("execl failed!\n");
13
14 perror("Why failed");
15
16 }
17
18 printf("after execl\n");
19
20 return 0;
21 }
#include
#include
#include
#include
#include
#include
#include
int main()
{
pid_t pid;
int data=10;
while(1){
printf("plase int data\n");
scanf("%d",&data);
if(data==1){
int fdSrc;
pid= fork();
if(pid>0){
wait(NULL);
}
if(pid==0){
char *readbuf=NULL;
fdSrc= open("TEST.config",O_RDWR);
int size= lseek(fdSrc,0,SEEK_END);
lseek(fdSrc,0,SEEK_SET);
readbuf=(char *)malloc(sizeof(char)*size+8);
int n_read=read(fdSrc,readbuf,size);
char *p= strstr(readbuf,"RNG=");
if(p==NULL){
printf("jieshu\n");
exit(-1);
}
p=p+strlen("RNG=");
*p= '5';
lseek(fdSrc,0,SEEK_SET);
int n_write = write(fdSrc,readbuf,strlen(readbuf));
close(fdSrc);
exit(0);
}
}else {
printf("wait do nothing\n");
}
}
return 0;
}
代码:
#include
#include
#include
#include
#include
#include
#include
int main()
{
pid_t pid;
int data=10;
while(1){
printf("plase int data\n");
scanf("%d",&data);
if(data==1){
int fdSrc;
pid= fork();
if(pid>0){
wait(NULL);
}
if(pid==0){
//execl("./changnew","changnew","TEST.config",NULL);
system("./changnew TEST.config");
}
}else {
printf("wait do nothing\n");
}
}
return 0;
}
参数说明:
popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c来执行参数command的指令。
参数type可使用“r”代表读取,“w”代表写入。依照此type值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中。
如果 type 为 r,那么调用进程读进 command 的标准输出。
如果 type 为 w,那么调用进程写到 command 的标准输入。
返回值: 若成功则返回文件指针,否则返回NULL,错误原因存于errno中
代码示例:
#include
#include
#include
int main()
{
char ret[1024]={0};
FILE *fp;
fp=popen("ps","r");
int nread=fread(ret,1,1024,fp);
printf("read ret:%d,ret=%s\n",nread,ret);
return 0;
}