我有一个非常简单的程序:
void main()
{
fgets(buf,133,stdin);
printf( buf);
system("/bin/dash");
}
当我启动程序时,一切正常,我可以输入任何我想要的东西然后我有一个shell。但是,如果我这样做
$ echo 'blabla' | ./test
为了自动填充buf(不用键盘输入任何内容),执行shell,但/ bin / ls工作正常。 (显然显示命令工作正常)
如果我删除fgets行,并执行相同的命令,它会起作用,但将'blabla'作为/ bin / dash的参数。但是,添加一个空字符或返回'\ xd'以模拟我的键盘在fgets中的返回不起作用
我想了解当我使用'|'时会发生什么我的c ++程序中的符号。我认为这是自动填充scanfs和fgets而无需任何人工干预的解决方案,我做错了还是还有其他解决方案?
谢谢。
Debian,C ++ g ++
答案 0 :(得分:5)
在shell中执行echo 'blabla' | ./test
时,shell将启动echo
进程并将其标准输出管道连接到./test
的标准输入管道。这与C ++无关:这些管道是大多数操作系统的一个特性,几乎每个进程都有它们。
当您的程序执行system
时,您正在创建一个连接到相同标准输入管道的新流程(或多个流程)。因此,如果echo
未读取该管道中的某些数据(来自test
命令),则可以通过system
启动的进程读取该数据。
使用echo
和管道是向fgets
和scanf
提供输入的好方法。将数据传递给程序的另一种方法是使用环境变量或命令行参数,但是您需要修改代码以检查这些内容。
答案 1 :(得分:2)
如果我理解正确,您希望为fgets
和shell提供输入,而是在管道传输时发现shell没有收到任何输入。
这是因为libc将缓冲fgets
的输入数据。
不是读取blabla\n
中的7个字节并将其余部分传递给shell,而是读取最多4096个字节(取决于系统),并将剩余的4089个字节用于将来fgets
/ {{1调用stdin。这些数据将存储在程序内部,并且不会被其他从底层流读取的进程使用,例如调用的shell。
当您以交互方式运行并在键盘上键入时,只有7个字节 当你按Enter键时可用,所以缓冲区只填充7个字节。因此,您输入的其余数据可供shell使用。你可以在你的错误程序中模拟相同的效果,并在输入中策略性地放置延迟:
f*
您可以通过将缓冲区大小设置为1个字节来避免此问题,以便{ echo "for fgets"; sleep 1; echo "ls"; } | ./foo
永远不会读取超过必要的内容:
fgets
现在您可以使用管道运行它并且没有延迟:
#include <stdio.h>
char input_buffer[1];
void main(int argc, char** argv)
{
char buf[133];
setvbuf(stdin, input_buffer, _IOFBF, 1);
fgets(buf,133,stdin);
printf( buf);
system("/bin/dash");
}