C:输出解析两次时如何避免重复 popen?

问题描述

我想解析 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,v3,unused);

    f = popen("ip -V","r"); // Todo: how to avoid repeating popen()?
    fscanf(f,iproute2-%d.%d.%d",&v3);
    printf("%d.%d.%d\n",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,SEEK_SET);rewind(f); 没有帮助。 我必须错过一些明显的东西。

解决方法

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

为了完成这项任务,您可以使用 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