李成笔记网

专注域名、站长SEO知识分享与实战技巧

C语言中popen 函数使用

popen 函数用于创建一个管道来与一个进程通信。这个函数允许你在 C 程序中执行一个 shell 命令,并根据指定的模式读取命令的输出或向命令发送输入。

语法

FILE *popen(const char *command, const char *type);
  • command: 要在 shell 中执行的命令。
  • type: 模式,可以是:

"r": 读取命令的输出。

"w": 向命令写入输入。

返回值

返回一个 FILE * 指针,可以用标准文件 I/O 函数(如 fgets、fprintf 等)来操作。

如果操作失败,返回 NULL。

工作原理

内部实现: popen 的内部操作包括:

  • 创建一个管道(单向通信通道)。
  • 通过 fork 创建一个子进程。
  • 子进程执行指定的 shell 命令。
  • 父进程返回一个连接到管道的 FILE * 指针。

应用场景

1. 捕获命令输出

你可以使用 popen 执行一个 shell 命令,并直接在你的 C 程序中捕获其输出。

示例: 列出当前目录中的文件。

#include <stdio.h>

int main() {
    FILE *pipe = popen("ls -l", "r");
    char buffer[128];

    if (pipe == NULL) {
        perror("popen 失败");
        return 1;
    }

    while (fgets(buffer, sizeof(buffer), pipe) != NULL) {
        printf("%s", buffer);
    }

    pclose(pipe);
    return 0;
}

使用注意事项

资源管理: 始终使用 pclose 关闭由 popen 打开的管道,以避免资源泄漏。

安全性: 对于 command 字符串,特别是包含用户输入的情况,要小心 shell 注入漏洞。

一个实例介绍(部分代码):

snprintf(cmd, sizeof(cmd), "sudo lsusb -d %x:%x", MCU_VENDOR_ID, MCU_PRODUCT_ID);
FILE *lsusb_pipe = popen(cmd, "r");
if (lsusb_pipe == NULL) 
{
    rc = -1;
    goto Exit;
}
while (fgets(line, sizeof(line), lsusb_pipe) != NULL && index < MAX_DEVICES) 
{
    char bus[10], device[10];
    if (sscanf(line, "Bus %s Device %s", bus, device) == 2) 
    {
        sprintf(devices[index], "/dev/bus/usb/%s/%s", bus, device);
         index++;
    }
}
  • 使用 snprintf 构建了命令字符串 cmd,这个函数能够安全地格式化并存储要执行的命令。
  • 构建的命令是 sudo lsusb -d <MCU_VENDOR_ID>:<MCU_PRODUCT_ID>,用于根据指定的厂商和产品 ID 过滤 USB 设备。

    • 代码使用 fgets 函数逐行读取 lsusb 命令的输出。

    每行内容都会检查是否符合预期格式("Bus <bus> Device <device>"),如果符合,则使用 sscanf 提取出总线和设备编号。

    • 提取出的总线和设备编号随后被用来构建 USB 设备文件的路径,并存储在 devices 数组中。

    发表评论:

    控制面板
    您好,欢迎到访网站!
      查看权限
    网站分类
    最新留言