如何使用 sscanf 从相似的行中读取特定数字?

How to read in a specific number with sscanf from lines which are similar?

我正在尝试使用 C 标准库中的 sscanf() 函数从文件中读取特定数字。我的示例数据来自 /proc/stat 系统 运行 a Linux Kernel。外观如下:

cpu  90158 11772 50095 6885572 36975 0 207 0 0 0
cpu0 22942 2975 12847 1720241 9655 0 58 0 0 0
cpu1 23879 2979 12080 1717405 12483 0 45 0 0 0
cpu2 21510 3105 12864 1722238 7790 0 57 0 0 0
cpu3 21824 2712 12301 1725687 7044 0 45 0 0 0
.
.
.
intr 2108705 19 28724 0 0 0 0 0 0 1 90871 0 0 204911 0 0 0 143 0 0 0 0 35 0     0 0 0 2362 0 101810 25 388 0 404786 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
ctxt 11136028
btime 1423918994
processes 155184
procs_running 2
procs_blocked 1
softirq 2109698 8 644880 168 19330 95660 0 24557 551780 3897 769418

我尝试打印 if 语句之后的所有行,但包含 cpu 的行除外(没有空格)紧跟数字。那是第一行 cpu 应该与所有其他人一起打印,但例如不是第二行 cpu0。此外,这些行中 cpu 之后的数字应作为 int 存储到 int cpu 中。

我真的试着解决这个问题,我至少可以通过使用字符 类 来打印正确的行。我的 if-语句包含:

sscanf(line, "cpu%*1[^ ]%d", &cpu) != 1)

其中 %1[^ ] 表示在行中读取直到遇到单个空格(可能不需要 1),然后将以下数字 %d 存储在 int cpu.但是 cpuN 行存储了错误的值。不是存储 0, 1, 2, 3 而是存储值 22942, 23879, 21510, 21824。现在这可以追溯到我对 %1[^ ] 的使用。但是我尝试了很多不同的东西,以至于我可能会错过显而易见的东西。我如何打印除 cpu 后跟数字 N 并在 int cpu 中存储 N 的行以外的所有行? (如果可能,我想避免使用 regex.h。)这是我目前的代码:

#include <stdio.h>
#include <stdlib.h>

main(void)
{
    FILE * fp;
    char * line = NULL;
    size_t len = 0;
    ssize_t read;

    fp = fopen("/proc/stat", "r");
    if (fp == NULL)
        exit(EXIT_FAILURE);

    while ((read = getline(&line, &len, fp)) != -1) {
        int cpu;
         if (sscanf(line, "cpu%*1[^ ]%d", &cpu) != 1) {
            printf("%s", line);
        }
    }

    fclose(fp);
    if (line)
        free(line);
    exit(EXIT_SUCCESS);
}

建议:

1) 将行读入缓冲区

2) strncmp (buffer, "cpu ") if 0, ignore line // notice trailing space

3) strncmp (buffer, "cpu" ) if 0, saved = atoi( buffer[3] ) // 没有尾随 space

4) 忽略所有其他行

您不想禁止分配 cpu 之后的数字。但是,您也不想跳过空白,因此您需要使用 %c%[],因为所有其他格式(除了 %n,这绝对不算在内contex) 跳过前导空格。反过来,这意味着您需要读取一个字符串,而不是一个整数。所以,代码应该是:

char cpu_str[8];  // Allow for big machines!
if (sscanf(line, "cpu%7[^ ]", cpu_str) != 1)
    printf("%s", line);
else if (sscanf(cpu_str, "%d", &cpu) != 1)
    …oops: may the scanset should be %7[0-9]…
else
    …cpu contains the cpu number…