- 🐚作者简介:花神庙码农(专注于Linux、WLAN、TCP/IP、Python等技术方向)
- 🐳博客主页:花神庙码农 ,地址:https://blog.csdn.net/qxhgd
- 🌐系列专栏:Linux技术
- 📰如觉得博主文章写的不错或对你有所帮助的话,还望大家三连支持一下呀!!! 👉关注✨、点赞👍、收藏📂、评论。
- 如需转载请参考转载须知!!
popen+fgets函数无法读取到命令输出的问题分析小结
popen及fgets使用基础
函数原型
#include <stdio.h>
FILE * popen ( const char * command , const char * type );
int pclose ( FILE * stream );
char *fgets(char *s, int size, FILE *stream);
功能说明
- The popen() function shall execute the command specified by the string command. It shall create a pipe between the calling program and the executed command, and shall return a pointer to a stream that can be used to either read from or write to the pipe.
- popen()会调用fork()产生子进程,之后,子进程中会调用/bin/sh -c来执行参数command的指令。
- 参数type可使用“r”代表读取,“w”代表写入。依照此type值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,并返回一个文件指针。
- 之后进程便可利用此文件指针,通过fgets等函数来读取子进程的输出设备或是写入到子进程的标准输入设备中。
execl(shell path, “sh”, “-c”, command, (char *)0); - 此外,除了fclose()以外,所有使用文件指针(FILE*)操作的函数均可以使用。
代码示例
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fp;
char buffer[128];
// 使用 popen 执行 echo 命令
fp = popen("echo Hello, World!", "r");
if (fp == NULL) {
perror("popen failed");
return 1;
}
// 使用 fgets 从标准输出读取数据
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
printf("Output: %s", buffer);
}
// 关闭管道
pclose(fp);
return 0;
}
使用场景
- 在驱动开发过程中,经常有下面的需求:
1)用户态执行某个命令;
2)读取并解析该命令的输出;
3)根据获取的参数值做进一步的处理。
常见的问题及分析
存在的问题
- 有时,会出现命令在串口有输出,但是通过popen+fgets的方式,却读取不到任何数据。有的命令则没有这个问题。
不同命令的情况及处理方式
用户态输出的程序
- 专有命令,如iwpriv、hostapd_cli等,均是在application中使用printf等函数进行输出;
- 通用命令,如cat,也是在用户态进行输出:
cat /proc/sys/net/netfilter/nf_conntrack_max
- 这种程序,使用前面的popen+fgets的方式是没有问题的。
内核态输出的程序
- 还有一类程序,虽然是用户态程序,但会通过ioctl等进入内核,并在内核中通过printk进行串口输出。
- 这种程序,使用前面的popen+fgets的方式是无法获取到命令输出的。
- 对于这种程序,可做适当改造:
– 通过ioctl进入内核,然后通过copy_to_user的方式,将内核数据copy到用户态;
– 之后,可直接使用数据或在用户态输出均可。
小结
- 关于两种命令的不同表现,大概原因是用户态输出的程序,使用的是标准输出,因此,popen的管道是可以连接过去的。而内核态输出的程序,使用的是printk,不是标准输出,因此,dup等函数对此无能为力。
如本文对你有些许帮助,欢迎大佬支持我一下(点赞+收藏+关注、关注公众号等),您的支持是我持续创作的竭动力
支持我的方式