linux--进程(3)exec族. system. popen

exec族函数

exec函数族分别是:execl, execlp, execle, execv, execvp, execvpe
函数原型

#include <unistd.h>
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族

我们用fork函数创建新进程后,经常会在新进程中调用exec函数去执行另外一个程序。当进程调用exec函数时,该进程被完全替换为新程序。因为调用exec函数并不创建新进程,所以前后进程的ID并没有改变。

execl

l : 使用参数列表

int execl(const char *path, const char *arg, ...);

示例1
//achoarg.c文件

#include<stdio.h>
int main(int argc,char **argv)
{
        int i=0;
        for(i;i<argc;i++){
             printf("argv[%d]%s\n",i,argv[i]);
        }

        return 0;
}

//exec.c文件

 #include <unistd.h>
 #include <stdio.h>
int main()
{
        printf("before execl\n");
        if(execl("./achoarg","achoarg","abc",NULL)==-1){
                printf("execl failed\n");   
                perror("why");//打印出错误原因
        }
        printf("after exexl\n");
        return 0;
}

结果:

before execl
argv[0]achoarg
argv[1]abc

//为什么没有 after exexl 这句话打印?
//文件echoarg的作用是打印命令行参数。然后再编译execl.c并执行execl可执行文件。用execl 找到并执行echoarg,将当前进程main替换掉,所以”after execl” 没有在终端被打印出来。
示例2

int main()
{

        printf("before execl\n");
        if(execl("/bin/ls","ls","-l",NULL)==-1){
                printf("execl failed\n");
                perror("why");
        }
        printf("after exexl\n");
        return 0;
}

执行结果就跟“ls -l”命令 的结果一样
注:
ls指令的地址 可以用“whereis ls ” 来查看

示例3

int main()
{
        printf("this pro is system date\n");
        if(execl("/bin/date","date",NULL)==-1){

                printf("execl failed\n");
                perror("why");
        }
        printf("after exexl\n");
        return 0;
}

在这里插入图片描述

execlp

p:使用文件名,并从PATH环境进行寻找可执行文件
(如果使用的可执行文件在PATH里,则使用execlp可以不用详细描述绝对路径)

echo $PATH 可以直接打印出环境变量
如果想要在环境变量添加路径:expor PATH= $PATH:需要添加的路径(pwd获得)

示例

 #include <unistd.h>
 #include <stdio.h>
int main()
{
        printf("this pro is system date\n");
        if(execlp("date","date",NULL)==-1){
//这时候第一个参数的date不用写详细路径了
                printf("execl failed\n");
                perror("why");
        }
        printf("after exexl\n");
        return 0;
}

execv和execvp

v:应先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数的参数。
execv

int main()
{

        printf("this pro is system date\n");

         char *arvg[]={"date",NULL};
     //  定义一个指向各个参数的指针数组
        if(execv("/bin/date",arvg)==-1){

                printf("execl failed\n");
                perror("why");
        }
        printf("after exexl\n");
        return 0;
}

execvp
同理就是第一个参数的路径在环境变量中,就可以直接写名字

int main()
{

        printf("this pro is system date\n");
        char *arvg[]={"date",NULL};
        if(execvp("date",arvg)==-1){
//第一个参数直接用 date  不需要加路径了
                printf("execl failed\n");
                perror("why");
        }
        printf("after exexl\n");
        return 0;
}

exec和fork相结合的示例

已知change在当前路径,它可以对当前目录中的config.txt文件里面的一个指定字符进行修改。 “./change config.txt”

int main()
{//不断检测用户输入,如果输入为1,则创建子进程来调用exec函数
        pid_t pid;
        int data;
        int fd;
        while(1){
              printf("please imput data:\n");
              scanf("%d",&data);
              if(data==1){
                      pid=fork();
                      if(pid>0){

                          wait(NULL);
                          //父进程等待子进程exec执行完,才会继续往下执行
                          printf("*****\n");
                      }
                      if(pid==0){
                        printf("%d\n",getpid());
                        execl("./change","./change","config.txt",NULL);
                        //用exec来执行change 从而实现更改字符的功能
                      }
               }else{
                      printf("do nonthing!\n");
               }
        }
        return 0;
}

分析:好处就是可以使代码简洁,不需要将change的代码复制到子进程当中去。

system

函数原型

int system(const char * string);

注:
执行指令 ./a.out
或者sh -c ./a.out

返回值
system()函数的返回值如下:
成功,则返回进程的状态值;
当sh不能执行时,返回127;
失败返回-1;
示例1(在上一段代码只需要修改一行代码)

execl("./change","./change","config.txt",NULL);

改成

system("./change config.txt");//直接写正常的执行指令格式就可

执行的效果和下面在终端执行的指令得到的效果一样
在这里插入图片描述
示例2

int main()
{
        printf("this pro is system date\n");
        int status=system("date");
        printf("%d\n",status);
        printf("%d\n",WEXITSTATUS(status));//返回的值需要解析

        printf("after system\n");//和exec的区别就是,调用system后还是会执行这行代码
        //而exec函数调用成功后,mian函数被替换了,直接执行exec里面运行的程序。
        return 0;
}

popen

函数原型:

 FILE *popen(const char *command, const char *type);

popen比system的优点是,popen可以获取运行的输出结果

参数说明:
command:
是一个指向以 NULL 结束的 shell 命令字符串的指针。这行命令将被传到 bin/sh 并使用 -c 标志,shell 将执行这个命令。
type:
如果 type 是 “r” 则表示读
如果 type 是 “w” 则表示写
r和w是相对command的管道而言的。r表示command从管道中读入,w表示 command通过管道输出到它的stdout

返回值:
若成功则返回文件指针,否则返回NULL,错误原因存于errno中

system的结果

int main()
{
        printf("this pro is system date\n");
        int c;
        c=system("ps");
        printf("c=%d\n",c);
        return 0;
}

在这里插入图片描述

popen的结果

int main()
{

        printf("this pro is system date\n");
        FILE *fp;
        char readBuf[1024]={0};
        fp=popen("ps","r");
        //如果参数为w,则会直接把内容输出在终端界面上
        int n=fread(readBuf,sizeof(char),1024,fp);
        printf("readbuf=\n%s\n",readBuf);
        printf("%d byt\n",n);
        pclose(fp);
        return 0;
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值