Linux系统学习——exec族函数、system函数、popen函数学习

导读:本篇文章讲解 Linux系统学习——exec族函数、system函数、popen函数学习,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

Linux系统学习——exec族、system、popen篇

一、exec族解析

1.头文件:

#include <unistd.h>

2.exec族函数的作用:

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

3.函数原型:

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

int execlp(const char *file, const char *arg, ...);

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

int execvp(const char *file, char *const argv[]);
参数说明:
path:可执行文件的路径名字 

arg:可执行程序所带的参数,第一个参数为可执行文件名字,没有带路径且arg必须以NULL结束 

file:如果参数file中包含/,则就将其视为路径名,否则就按 PATH环境变量,在它所指定的各目录中搜寻可执行文件

返回值: 
exec函数族的函数执行成功后不会返回,调用失败时,会设置errno并返回-1,然后从原程序的调用点接着往下执行。

exec族函数参数极难记忆和分辨,函数名中的字符会给我们一些帮助: 
l : 使用参数列表 
p:使用文件名,并从PATH环境进行寻找可执行文件 
v:应先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数的参数
e:多了envp[]数组,使用新的环境变量代替调用进程的环境变量

(1)execl函数解析:

以文件echoarg为例:

文件echoarg.c

  1 #include <stdio.h>
  2 
  3 int main(int argc,char *argv[])
  4 {
  5     int i = 0;
  6     for(i = 0; i < argc; i++)
  7     {
  8         printf("argv[%d]: %s\n",i,argv[i]);
  9     }
 10     return 0;
 11 }

jc11.c(execl第一个参数路径不同与jc12.c对比)

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 //函数原型:int execl(const char *path, const char *arg, ...);
  5 
  6 int main(void)
  7 {
  8          printf("before execl\n");
  9 		//如果execl执行成功,就不会执行execl以下的全部语句
 10         if(execl("./bin/echoarg","echoarg","abc",NULL) == -1) //以当前目录下bin文件夹下echoarg文件打开
 11          {
 12                 printf("execl failed!\n"); 
 13 
 14                 perror("Why failed"); 	//打印错误
 15 
 16         }
 17 
 18         printf("after execl\n"); //如果execl执行成功,就不会执行execl以下的全部语句
 19 
 20         return 0;
 21 }

jc11.c运行结果:

在这里插入图片描述

jc12.c(echoarg在当前目录正确路径下演示)

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 //函数原型:int execl(const char *path, const char *arg, ...);
  5 
  6 int main(void)
  7 {
  8          printf("before execl\n");
  9 
 10         if(execl("./echoarg","echoarg","abc",NULL) == -1) 	//打开当前目录下echoarg文件
 11          {
 12                 printf("execl failed!\n");
 13 
 14                 perror("Why failed");  	//打印错误原因
 15 
 16         }
 17 
 18         printf("after execl\n");   如果execl执行成功,就不会执行execl以下的全部语句
 19 
 20         return 0;
 21 }

jc12.c运行结果:

在这里插入图片描述

原理:

  1. 我们先用gcc编译echoarg.c,生成可执行文件echoarg并放在当前路径 ./ 目录下(而不是bin目录)

  2. 文件echoarg的作用是打印命令行参数。然后再编译 jc12.c 并执行 jc12.c可执行文件

  3. 用execl 找到并执行echoarg,将当前进程main替换掉,所以”after execl” 没有在终端被打印出来。

(2)execlp函数解析:

1.与execl函数对比:

execl函数下

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 //函数原型:int execl(const char *path, const char *arg, ...);
  5 
  6 int main(void)
  7 {
  8          printf("before execl\n");
  9 
 10         if(execl("ps","ps",NULL,NULL) == -1) //执行ps命令查看进程
 11          {
 12                 printf("execl failed!\n");
 13 
 14                 perror("Why failed");
 15 
 16         }
 17 
 18         printf("after execl\n");
 19 
 20         return 0;
 21 }

结果演示:

在这里插入图片描述
上面这个例子因为参数没有带路径,所以execl找不到可执行文件。
下面再看一个例子对比一下:

使用execlp函数

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 //函数原型:int execl(const char *path, const char *arg, ...);
  5 
  6 int main(void)
  7 {
  8          printf("before execl\n");
  9 
 10         if(execlp("ps","ps",NULL,NULL) == -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 }

结果演示:
在这里插入图片描述

总结:

(1)execlp可以在参数中不用具体的路径,也可以找到可执行文件并执行该指令,反之execl需要指定具体的文件路径的位置(如./ ),这样execl才能找到可执行文件

(2)可以看出,上面的exaclp函数带p,所以能通过环境变量PATH查找到可执行文件ps

(3)execl需要在第一个参数打上该文件的路径,而execlp则可以根据环境变量,直接打名字访问

补充:

环境路径查找 : 使用pwd
环境变量查询 : 使用 $PATH
环境变量的添加 : export PATH=$PATH : (你想加的路径)

带 v 不带 l 的一类exec函数,包括execv、execvp、execve,应先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数的参数。 如char *arg[]这种形式,且arg最后一个元素必须是NULL,例如 char *arg[] = {“ls”,”-l”,NULL};

(3)execv函数解析:

  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 } 

结果展示:
在这里插入图片描述

(4)execvp函数

  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(execvp("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 }     

结果展示:
在这里插入图片描述

execv和execvp对比:

1.execv需要添加指令的具体路径,而execvp则可以直接根据环境变量设置中直接进行访问指令
2.两者在设定中都要以NULL空指针为结尾

exec函数中可以添加perror来获取运行失败的调试信息

exec函数调用执行成功后,都不会继续往下执行代码

二、system函数

(1)概念

在这里插入图片描述

(2)使用system

简单粗暴修改:
在这里插入图片描述

  1 #include<stdio.h>
  2 #include <sys/types.h>
  3 #include <unistd.h>
  4 #include<sys/stat.h>
  5 #include<fcntl.h>
  6 #include<unistd.h>
  7 #include<string.h>
  8 #include<stdlib.h>
  9 
 10 int main()
 11 {
 12         pid_t pid;
 13 
 14         int data;
 15         while(1)
 16         {
 17                 printf("Please input you data :\n");
 18                 scanf("%d",&data);
 19 
 20                 if(data == 1)
 21                 {
 22                         pid = fork();
 23 
 24                         if(pid>0)
 25                         {
 26                                 wait(NULL);
 27                         }
 28 
 29                         if(pid == 0)
 30                         {
 31                 //              execl("changeData","changeData","config.txt",NULL);
 32                                 system("./changeData config.txt");
 33                                 exit(0);
 34 
 35                         }
 36                 }
 37                 else
 38                 {
 39                         printf("wait do nothing\n");
 40                 }
 41         }
 42 
 43         return 0;
 44 }

在这里插入图片描述
2.
在这里插入图片描述

在这里插入图片描述

可以通过sh –c +你输入的指令名,来获取提示信息。

三、popen函数

popen函数解析:

函数原型:

#include “stdio.h”
FILE popen( const char command, const char* mode )

参数说明:

  • command: 是一个指向以 NULL 结束的 shell 命令字符串的指针。这行命令将被传到 bin/sh 并使用 -c
    标志,shell 将执行这个命令。
  • mode: 只能是读或者写中的一种,得到的返回值(标准 I/O 流)也具有和 type 相应的只读或只写类型。如果 type 是 “r” 则文件指针连接到 command 的标准输出;如果 type 是 “w” 则文件指针连接到 command 的标准输入。

返回值:

如果调用成功,则返回一个读或者打开文件的指针,如果失败,返回NULL,具体错误要根据errno判断

代码演示:

在这里插入图片描述

在这里插入图片描述

结论:

popen和system相比,popen可以将指令输出的结果打印出来,而system却不能。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/68485.html

(0)
newbe的头像newbebm

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!