繁体   English   中英

如何使用pipe和scanf()读取命令输出?

[英]How to read a command output with pipe and scanf()?

我需要能够发送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的整个段落输出。

任何帮助将不胜感激。 谢谢。

一种可能性: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;
}

scanf文档说

这些函数返回成功匹配和分配的输入项的数量,该数量可能少于所提供的数量,在早期匹配失败的情况下甚至为零。 如果在第一次成功转换或匹配失败发生之前到达输入结束,则返回EOF值。 如果发生读取错误,也会返回EOF,在这种情况下,将设置流的错误指示符(请参阅ferror(3)),并且设置errno表示错误。

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

您是否考虑过编写一个调用scanf的循环,监视其返回值并在EOF发生时中断

考虑以下在标准C中实现的readall()函数:

#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或通过popen()打开的管道popen()读取到动态分配的缓冲区中,追加一个nul字节( \\0 ),然后返回指向该缓冲区的指针。 如果不是NULL,则读取的实际字符数(因此,不包括附加的nul字节)存储在第二个参数指向的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个nul字节。 (我之所以喜欢这样,是有原因的,但是这都是推测性的,并且是我倾向于使用的C库所特有的,因此并不重要。)

尽管上面使用的方法可以正常工作,但是如果您愿意,可以更改size_new计算。 只要确保它们至少都已used + 1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM