Как прочитать вывод команды с помощью pipe и scanf ()? - PullRequest
0 голосов
/ 24 ноября 2018

Мне нужно иметь возможность отправлять вывод команды GET и сохранять его в переменной внутри моей программы, в настоящее время я делаю это так:

GET google.com |./myprogram

И получить его в моей программе со следующим кодом:

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

int main(int argc, char *argv[]){
  char *a = (char *) malloc (10000000);
  scanf("%[^\n]", a);
  printf("%s\n",a);

return 0;
}

Проблема у меня заключается в том, что функция scanf останавливается на новой строке, и мне нужночтобы иметь возможность хранить весь вывод абзаца из GET.

Любая помощь будет оценена.Спасибо.

Ответы [ 3 ]

0 голосов
/ 24 ноября 2018

Одна возможность: GET включает информацию о размере в заголовки?Не могли бы вы использовать это, чтобы определить, сколько места выделять и сколько данных читать?Это, однако, непросто и требует чтения данных в дрейфах и потрохах.

Проще говоря, рассмотрите возможность использования POSIX (и Linux) getdelim() (близкий родственник getline()) и укажите разделитель как нулевой байт.Это вряд ли появится в выводе GET, поэтому весь контент будет одной строкой, а getdelim() автоматически выделит необходимое количество места.Он также говорит вам, как долго были данные.

#include <stdio.h>

int main(void)
{
    char *buffer = 0;
    size_t buflen = 0;
    int length = getdelim(&buffer, &buflen, '\0', stdin);
    if (length > 0)
        printf("%*.*s\n", length, length, buffer);
    free(buffer);
    return 0;
}
0 голосов
/ 24 ноября 2018

Рассмотрим следующую функцию readall(), реализованную в стандартном C:

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

char *readall(FILE *source, size_t *length)
{
    char   *data = NULL;
    size_t  size = 0;
    size_t  used = 0;
    size_t  n;

    /* If we have a place to store the length,
       we initialize it to zero. */
    if (length)
        *length = 0;

    /* Do not attempt to read the source, if it is
       already in end-of-file or error state. */
    if (feof(source) || ferror(source))
        return NULL;

    while (1) {

        /* Ensure there is unused chars in data. */
        if (used >= size) {
            const size_t  new_size = (used | 65535) + 65537 - 32;
            char         *new_data;

            new_data = realloc(data, new_size);
            if (!new_data) {
                /* Although reallocation failed, data is still there. */
                free(data);
                /* We just fail. */
                return NULL;
            }

            data = new_data;
            size = new_size;
        }

        /* Read more of the source. */
        n = fread(data + used, 1, size - used, source);
        if (!n)
            break;

        used += n;
    }

    /* Read error or other wonkiness? */
    if (!feof(source) || ferror(source)) {
        free(data);
        return NULL;
    }

    /* Optimize the allocation. For ease of use, we append
       at least one nul byte ('\0') at end. */
    {
        const size_t  new_size = (used | 7) + 9;
        char         *new_data;

        new_data = realloc(data, new_size);
        if (!new_data) {
            if (used >= size) {
                /* There is no room for the nul. We fail. */
                free(data);
                return NULL;
            }
            /* There is enough room for at least one nul,
               so no reason to fail. */
        } else {
            data = new_data;
            size = new_size;
        }
    }

    /* Ensure the buffer is padded with nuls. */
    memset(data + used, 0, size - used);

    /* Save length, if requested. */
    if (length)
        *length = used;

    return data;
}

Она читает все из указанного дескриптора файла (который может быть стандартным потоком, таким как stdin, или каналом, открытым через * 1006).*) в динамически размещенный буфер, добавляет нулевой байт (\0) и возвращает указатель на буфер.Если не NULL, фактическое число прочитанных символов (т.е. не включая добавленный нуль-байт) сохраняется в size_t, указанном вторым параметром.

Вы можете использовать его для чтения вывода двоичных данныхпо программам, скажем, dot -Tpng diagram.dot или конвертеры изображений, или даже wget -O - выходные данные (получение данных с определенных URL-адресов, текстовых или двоичных файлов).

Вы можете использовать это, например, таким образом:

int main(void)
{
    char    *src;
    size_t   len;

    src = readall(stdin, &len);
    if (!src) {
        fprintf(stderr, "Error reading standard input.\n");
        return EXIT_FAILURE;
    }

    fprintf(stderr, "Read %zu chars.\n", len);

    /* As an example, print it to standard output. */    
    if (len > 0)
        fwrite(src, len, 1, stdout);

    free(src);
    return EXIT_SUCCESS;
}

Функция readall() имеет две причуды: она выделяет память примерно в 131072-байтовых блоках (но может варьироваться, если бы fread() должна была возвращать короткие чтения), и добавляет в буфер от 7 до 15 нулевых байтов.(Есть причины, по которым мне нравится делать это таким образом, но все они носят умозрительный характер и специфичны для библиотек C, которые я склонен использовать, поэтому это не важно.)

Хотя те, что использовались выше, работают нормально, выможете изменить size_new расчеты, если вы предпочитаете иначе.Просто убедитесь, что они оба по крайней мере used + 1.

0 голосов
/ 24 ноября 2018

Документация Scanf гласит:

Эти функции возвращают количество входных элементов, успешно сопоставленных и назначенных, которое может быть меньше предусмотренного или даже равно нулю в случае сбоя при раннем сопоставлении.Значение EOF возвращается, если достигнут конец ввода перед первым успешным преобразованием или ошибкой сопоставления.EOF также возвращается, если возникает ошибка чтения, и в этом случае устанавливается индикатор ошибки для потока (см. Ferror (3)), а значение errno указывает на ошибку.

https://www.freebsd.org/cgi/man.cgi?query=scanf&sektion=3

Рассматривали ли вы написание цикла, который вызывает scanf, отслеживает его возвращаемое значение и прерывается, если EOF

...