Linux下使用部分exec族函数,system函数,popen函数

发布时间:2024年01月18日

这篇博客很大程度上借鉴了三位大佬的博客,可以说是拾人牙慧,感谢三位大佬的分享,三篇博客的网址分别是

https://blog.csdn.net/u014530704/article/details/73848573

https://www.cnblogs.com/leijiangtao/p/4051387.html

https://blog.csdn.net/libinbin_1014/article/details/51490568

一、execl函数的使用

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

返回值:

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

参数说明:

path:可执行文件的路径名字

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

当进程调用exec族函数时,该进程被完全替换为新程序。因为调用exec函数并不创建新进程,所以前后进程的ID并没有改变

1.excel功能验证

首先我们先在当前路径下建立一个echoarg.c文件,代码如下

接着编译运行,创造一个可运行的echoarg文件,结果如下

接着我们利用excel编写代码,看一下该函数的功能

这里要说一下,当你使用excel函数的时候,第一个参数是文件路径,无论你是相对路径还是绝对路径一定要保证路径正确,否则是没办法成功使用excel函数的。同时还要注意,无论你的arg参数有多少个,最后一个一定是NULL,否则也无法成功调用。

运行结果如下,我们可以看到,当excel函数使用成功的时候,它就调用了echoarg文件,并且直接运行该文件的程序了,他原来的程序就不管了。

下面我们再来举出一些失败的例子

案例一:路径不对,代码如下图所示(我的echoarg在当前路径,不是在bin路径下)

运行结果如下,可以看出,execl函数调用失败后返回-1。并且perror函数已经告诉了我们失败的原因,是路径的错误。

案例二:arg参数最后一个不是NULL ,代码如下

运行结果如下,可以看到,如果arg参数最后一个不是NULL,编译都无法通过

2.使用excel函数调用linux中的一些命令

刚才的第一个例子写的是我们用excel函数调用自己写的可执行文件,那么接下来的例子中,我们要调用linux中的ls命令,,调用date命令

首先利用whereis命令查出来两个个指令的路径,如下图所示

案例一:调用ls命令,代码如下

运行结果如下,可以看到,确实执行了ls的功能

案例二:调用date命令,代码如下

运行结果如下,可以看到,却是执行了date功能

二、execlp函数的使用

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

如果参数file中包含/,则就将其视为路径名,否则就按 PATH环境变量,在它所指定的各目录中搜寻可执行文件。(个人觉得环境变量可以理解为当前可执行文件的路径)

参数

arg:可执行程序所带的参数,第一个参数为可执行文件名字,没有带路径且arg必须以NULL结束
file:如果参数file中包含/,则就将其视为路径名,否则就按 PATH环境变量,在它所指定的各目录中搜寻可执行文件。

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

1.验证按PATH环境变量,在它所指定的各目录中搜寻可执行文件。代码如下

这里我们的带一个参数是ps,它在bin路径下可以找到,然后我们的第二个参数是ps,就是要执行ps指令。

运行结果如下

2.如何修改环境变量

如果想要使用execlp函数,第一个参数还不想要写路径,那么你的第一个参数文件就必须在环境变量里。但是我们自己手写的文件是不会出现在系统默认的环境变量中的,如何让我我们写的文件出现在环境变量中呢?可以按照下面的操作

1

输入echo $PATH

查看系统默认的环境变量

2

输入cd 你手写的文件对应的文件夹

转到对应的文件夹

输入pwd

查看当前文件夹路径

输入export PATH=$PATH: 当前文件夹路径

向系统默认的环境变量中添加新的文件路径

输入echo $PATH

查看新的环境变量

按照上述步骤,即可配置完成,如下图所示

但是要强调的是,这种自己配置的环境变量是临时的,当关闭Shell终端后就失效了。

我的echoarg文件是在jingcheng的文件夹下,当我将它文件路径配置到环境变量中后,就可以使用excelp函数了

运行结果如下

三、system函数的使用

system原型

int system(const char *command);

参数是一个字符串常量

system()函数的返回值如下:

成功,则返回进程的状态值;

当sh不能执行时,返回127;

失败返回-1;

这是从大佬的博客里拷贝下来的system源码

#include

#include

#include

#include

int system(const char * cmdstring)

{

? pid_t pid;

? int status;

? if(cmdstring == NULL){

?????

????? return (1);

? }

? if((pid = fork())<0){

??????? status = -1;

? }

? else if(pid == 0){

??? execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);

??? -exit(127); //子进程正常执行则不会执行此语句

??? }

? else{

??????? while(waitpid(pid, &status, 0) < 0){

????????? if(errno != EINTER){

??????????? status = -1;

??????????? break;

????????? }

??????? }

??? }

??? return status;

}

要说的是execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);里的参数

sh -c 可执行文件路径就相当于可执行文件路径

意思就是sh -c ./a.out与./a.out等价

(char *)0就相当于NULL

通过观看源码,我们可以发现system函数中调用了execl函数,但是与execl不同的是,system使用后依旧会返回到原来的程序中去,去把原来的程序执行完。下面我们用代码验正一下。

个人对system函数理解:其实我感觉syetem就是一个变相的execl,为什么我会这样说呢看看下面这段代码

运行结果如下

还记得上文中的system的源码中的代码吗

execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);

cmdstring是一个字符串常量,对应于我写的./echoarg echoarg NUL。可以看到的是我写的字符串常量中给出了文件地址以及参数,而且虽然system函数调用了execl函数,但是我们使用system函数给参数的时候却不需要加上NULL(因为(char *)0就相当于NULL),而且我们写的一长串字符常量是通过空格被划分成了不同的参数,程序会自动识别。

本人能力有限,关于system函数就只能说这么多了,更多的细节可以参考文章开头大佬的博客。

四、popen函数的使用

FILE popen( const char *command, const char* mode )

参数说明:

Command:一个一个字符串常量,用法与system一样

mode:r代表读,w代表写

返回值:

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

int pclose (FILE* stream)

参数说明:

stream:popen返回的文件指针

返回值:

如果调用失败,返回 -1

作用:

popen() 函数用于创建一个管道:其内部实现为调用 fork 产生一个子进程,执行一个 shell 以运行命令来开启一个进程这个进程必须由 pclose() 函数关闭。

相比于system,popen函数可以获取程序运行的输出结果。什么意思呢?说白了就是system函数只能将数据在命令终端打印出来,但是popen函数还可以将你执行的数据内容留下来。

比如在下面的程序里,我们调用了popen函数后返回fp,接着使用fread函数,通过fp找到执行的数据内容读到缓冲区ret里,然后我们就还可以读出来了。

还不明白的话看看下面这个图

下面是验证的代码

运行结果如下图所示,可以看到通过fread读出来了程序运行的输出结果。

文章来源:https://blog.csdn.net/weixin_51374594/article/details/135669400
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。