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运行结果:
原理:
-
我们先用gcc编译echoarg.c,生成可执行文件echoarg并放在当前路径 ./ 目录下(而不是bin目录)
-
文件echoarg的作用是打印命令行参数。然后再编译 jc12.c 并执行 jc12.c可执行文件
-
用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 }
可以通过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