【问题标题】:C: how to avoid repeating popen when output parsed twice?C:输出解析两次时如何避免重复popen?
【发布时间】:2021-01-04 15:47:29
【问题描述】:

我想解析popen(3) 的输出,但看起来我必须重复popen() 调用。

#include <stdio.h>

int main(int argc, char *argv[]) {
    int v1, v2, v3;
    char unused[255];
    FILE *f;

    f = popen("ip -V", "r");

    fscanf(f, "ip utility, iproute2-v%d.%d.%d-%s", &v1, &v2, &v3, unused);
    printf("%d.%d.%d (%s)\n", v1, v2, v3, unused);

    f = popen("ip -V", "r"); // TODO: how to avoid repeating popen()?
    fscanf(f, "ip utility, iproute2-%d.%d.%d", &v1, &v2, &v3);
    printf("%d.%d.%d\n", v1, v2, v3);

    pclose(f);

    return 0;
}

在这个版本上测试:

$ ip -V
ip utility, iproute2-5.8.0

不重复,保持旧值:

$ ./fscanf-popen
32764.-1446225616.0 ()
32764.-1446225616.0

随着重复它会正确处理它:

$ ./fscanf-popen
32765.1933255568.0 ()
5.8.0

fseek(f, 0, SEEK_SET);rewind(f); 没有帮助。 我必须错过一些明显的东西。

【问题讨论】:

  • 如果我们想使用两次数据,你应该存储它。
  • 在第一次通话中,您有iproute2-v%d.%d.%d,格式字符串中有一个额外的vv 不在第二次尝试中。我建议你检查一下fscanf calls return
  • ...但在您的情况下,您只需要确保在格式字符串中使用 ,,并检查 scanf 返回的值。
  • 至于您的问题,将直到EOF 之前的所有输出读入内存缓冲区。然后改为解析该缓冲区。
  • @Someprogrammerdude 我删除了检查代码以简化示例。但即使有了代码,也需要更多尝试。

标签: c linux scanf popen


【解决方案1】:

您正在使用fscanf() 解析管道的输出,它使用来自流的输入直到它满足指定的格式。出于这个原因,没有进一步的fscanf 将只读取流中存在的任何新数据。相反,您需要将输入存储到一个字符串(chars 的数组)中。

为了完成这项任务,您可以使用fgets() 来阅读整行。通过这种方式,您将始终能够将存储的字符串传递给sscanf(),或执行检索字符串包含的值所需的任何其他解析操作:

char buf[1000];

f = popen("ip -V", "r");

if( f )
{
    char *ret = fgets(buf, 1000, f);

    if( ret )
    {
        sscanf(buf, "ip utility, iproute2-v%d.%d.%d-%s", &v1, &v2, &v3, unused); // or any other proper parsing action
        printf("%d.%d.%d (%s)\n", v1, v2, v3, unused);
    }

    /* ... */
  
    pclose(f);
}

fgets 只读取一行(保留尾随换行符)。如果你需要读取 N 行,只需迭代重复它,直到它返回 NULL

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-06
    • 2019-05-21
    • 1970-01-01
    • 2017-06-06
    • 2021-07-03
    • 2014-11-17
    相关资源
    最近更新 更多