exec族函数、system、popen

exec族函数函数的作用:
我们用fork函数创建新进程后,经常会在新进程中调用exec函数去执行另外一个程序。当进程调用exec函数时,该进程被完全替换为新程序。因为调用exec函数并不创建新进程,所以前后进程的ID并没有改变。
功能:
  在调用进程内部执行一个可执行文件。可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件。
函数族:
  exec函数族分别是:execl, execlp, execle, execv, execvp, execvpe
  函数原型:
1 int execl(const char *path, const char *arg, …);
2 int execlp(const char *file, const char *arg, …);
3 int execle(const char *path, const char *arg,…, char * const envp[]);
4 int execv(const char *path, char *const argv[]);
5 int execvp(const char *file, char *const argv[]);
6 int execvpe(const char *file, char *const argv[],char *const envp[]);
返回值:
  exec函数族的函数执行成功后不会返回,调用失败时,会设置errno并返回-1,然后从原程序的调用点接着往下执行。
  
参数说明:
path:可执行文件的路径名字
arg:可执行程序所带的参数,第一个参数为可执行文件名字,没有带路径且arg必须以NULL结束
file:如果参数file中包含/,则就将其视为路径名,否则就按 PATH环境变量,在它所指定的各目录中搜寻
可执行文件。
-
带l的一类exac函数(l表示list),包括execl、execlp、execle,要求将新程序的每个命令行参数都说明为 一个单独的参数。这种参数表以空指针结尾。
以execl函数为例子来说明:
exec主程序:

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

int main()
{
        printf("before execl!\n");
        if(execl("./echo","qwe","asd",NULL)==-1){
                printf("execl faied\n");
                perror("why");		//把错误解析出来
        }
        printf("after execl\n");
        return 0;
}
~     

跑一半exec调用的程序:

#include<stdio.h>
int main(int argc,char *argv[])
{
        int i;
        for(i=0;i<argc;i++){
                printf("argc[%d]:argv[%s]\n",i,argv[i]);
        }
        return 0;
}
结果:
before execl!
argc[0]:argv[qwe]
argc[1]:argv[asd]

exaclp函数带p,所以能通过环境变量PATH查找到可执行文件。就是说可以查找执行所有在环境变量下的文件。不用像execl那样要去找绝对路径。

execvp和execl的区别:
execvp就是把execl里参数用过一个地址封装。然后直接调用。实现的结果都是一样的。execv和execvp就像execl和execlp一样。区别在路径和环境变量。还是那句话,带p的只要在环境变量下都能执行,不带p的要绝对路径才能执行。
案例:

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

int main()
{
        printf("before execl!\n");
        char *arg[]={"qwe","asd",NULL};
        if(execvp("./echo",arg)==-1){
                printf("execl faied\n");
                perror("why");
        }
        printf("after execl\n");
        return 0;
}

环境变量:
如果查找当前环境变量:echo $PATH

CLC@Embed_Learn:~/LINUX/jincheng$ echo $PATH
/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/opt/FriendlyARM/toolschain/4.5.1/bin

如何把自己需要的路径配置到环境变量里:
1.先用pwd指令查找自己要的当前路径。

CLC@Embed_Learn:~/LINUX/jincheng$ pwd
/home/CLC/LINUX/jincheng

2.调用export配置环境变量,把自己要的路径复制进去

CLC@Embed_Learn:~/LINUX/jincheng$ export PATH=$PATH:/home/CLC/LINUX/jincheng
CLC@Embed_Learn:~/LINUX/jincheng$ echo $PATH
/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/opt/FriendlyARM/toolschain/4.5.1/bin:/home/CLC/LINUX/jincheng

这样就配置成功了。

小案例:
exec配合fork使用:
实现功能: 当父进程检测到1的时候,创建子进程把配置文件修改掉。
配置文件date1

QWE=1
ASD=2
ZXC=3

修改程序change.c

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include<stdlib.h>
#include<string.h>
int main()
{
        int fd;
        char readbuf[128]={"\0"};
        fd=open("./date1",O_RDWR);
        if(fd==-1){
                printf("open faild\n");
                exit(-1);
        }
        int size=lseek(fd,0,SEEK_END);
        lseek(fd,0,SEEK_SET);
        if(read(fd,readbuf,size)==-1){
                printf("read faild\n");
                exit(-1);
        }
//      printf("%s\n",readbuf);
        char *p=strstr(readbuf,"ASD=");
        if(p==NULL){
                printf("no date\n");
        }
        p=p+strlen("ASD=");
        *p='9';
        lseek(fd,0,SEEK_SET);
        if(write(fd,readbuf,size)==-1){
                printf("write faild\n");
        }
        close(fd);
        return 0;
}

创建进程通过execl调用change.c:

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

int main()
{
        int date;
        pid_t pid;
        while(1){
                printf("input you date\n");
                scanf("%d",&date);
        //      printf("%d\n",date);
                if(date==1){
                        pid=fork();
                        if(pid>0){
                                printf("fathar\n");
                        }else if(pid==0){
                                printf("child change\n");
                                execl("./change",NULL,NULL,NULL);
                        }
                }else{
                        printf("nothing\n");
                }
        }
        return 0;
}
结果:
CLC@Embed_Learn:~/LINUX/jincheng$ cat date1
QWE=1
ASD=2
ZXC=3
CLC@Embed_Learn:~/LINUX/jincheng$ ./a.out
input you date
2
nothing
input you date
3
nothing
input you date
1
fathar
input you date
child change
^C
CLC@Embed_Learn:~/LINUX/jincheng$ cat date1
QWE=1
ASD=9
ZXC=3

=============================================================
system 函数
函数原型: int system(const char *command);
参数: 要执行的路径名
返回值: 调用路径失败返回127,其他原因返回-1。

例子如上。改个进程调用程序:

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

int main()
{
        int date;
        pid_t pid;
        while(1){
                printf("input you date\n");
                scanf("%d",&date);
        //      printf("%d\n",date);
                if(date==1){
                        pid=fork();
                        if(pid>0){
                                printf("fathar\n");
                        }else if(pid==0){
                                printf("child change\n");
                                //execl("./change","change","date1",NULL);
                                system("./change");
                        }
                }else{
                        printf("nothing\n");
                }
        }
        return 0;
}
~                                                                                             
~     
结果:
CLC@Embed_Learn:~/LINUX/jincheng$ cat date1
QWE=1
ASD=2
ZXC=3
CLC@Embed_Learn:~/LINUX/jincheng$ gcc forkDate.c
CLC@Embed_Learn:~/LINUX/jincheng$ ./a.out
input you date
2
nothing
input you date
1
fathar
input you date
child change
input you date
^C
CLC@Embed_Learn:~/LINUX/jincheng$ cat date1
QWE=1
ASD=9
ZXC=3
                             

==============================================================================
popen 函数
popen比system好处是可以获取运行的结果。一般需要获取运行结果的时候用popen。
函数原型:FILE *popen(const char *command, const char *type);
参数:
command:是一个指向以NULL结束的shell命令字符串的指针。这行命令将被传到bin/sh并使用-C标志,shell 将执行这个命令。(执行指令路径名)
mode:只能是读或者写中的-种,得到的返回值(标准1/O流)也具有和type相应的只读或只写类型。如果type是"r” I则文件指针连接到command的标准输出;如果type是"w" 则文件指针连接到 command的标准输入。(输出:r 输入:w)。

返回值: .
如果调用成功,则返回一个读或者打开文件的指针,如果失败,返回NULL,具体错误要根据errno判断int pclcse (FILE* stream)
参数说明: stream: popen返回的文件指针
返回值:
如果调用失败,返回-1

案例:

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

int main()
{
        char ret[1024]={0};
        FILE *fp;
        fp=popen("ps","r");
        int nread=fread(ret,1,1024,fp);	// 文件流的用fread
        printf("%s\nread:%d\n",ret,nread);
        return 0;
}
结果:
 PID TTY          TIME CMD
 2219 pts/1    00:00:00 a.out
 2220 pts/1    00:00:00 sh
 2221 pts/1    00:00:00 ps
38261 pts/1    00:00:02 bash
61618 pts/1    00:00:00 wait
61619 pts/1    00:00:00 wait <defunct>

read:209

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值