![](/img/trans.png)
[英]How to pipe data to a program which calls scanf() and read() in Linux
[英]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.