我有一个非常简单的程序:
void main()
{
fgets(buf,133,stdin);
printf( buf);
system("/bin/dash");
}
当我启动程序时,一切都很好,我可以键入任何我想要的,然后我有一个外壳。不过,如果我做了
$ echo 'blabla' | ./test
为了自动填充buf (不使用键盘输入anyting ),可以执行shell,例如,/bin/ls可以正常工作。(很明显,显示命令工作正常)
如果删除fget行,并执行相同的命令,它将工作,但将'blabla‘作为/bin/dash的参数。但是,添加nul字符或返回'\xd‘以模拟我的键盘在fget中的返回是行不通的。
我想了解,当我在我的c++程序中使用‘\’符号时,会发生什么。我认为这是自动填充扫描和fget的解决方案,而不需要任何人的交互,我是做错了还是有其他的解决方案?
谢谢。
Debian,C++ g++
发布于 2015-09-01 09:14:29
如果我正确地理解了您,您希望同时向您的fgets
和您的shell提供输入,但是却发现当您管道时,shell没有接收到任何输入。
这是因为libc将为fgets
缓冲输入数据。
它不是读取blabla\n
中的7个字节,而是将其余的字节传递给shell,而是读取高达4096字节(系统依赖的),并将其余的4089字节用于stdin上的未来fgets
/f*
调用。这些数据将存储在程序内部,不能用于从底层流读取的其他进程,如调用的shell。
当您以交互方式运行并在键盘上键入时,当您点击enter时,只有7个字节可用,因此缓冲区只填充了7个字节。因此,您键入的其余数据对shell是可用的。您本可以在您的buggy程序中模拟同样的效果,在输入中有策略地放置延迟:
{ echo "for fgets"; sleep 1; echo "ls"; } | ./foo
您可以通过将缓冲区大小设置为1字节来避免此问题,这样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");
}
现在,您可以使用管道运行它了,并且没有任何延迟:
$ echo -e "for fgets\nls"
for fgets
ls
$ gcc foo.c -o foo
$ echo -e "for fgets\nls" | ./foo
for fgets
Desktop Downloads foo.c Pictures Steam Videos
Documents foo Music Public Templates win
发布于 2015-09-01 08:38:21
在shell中执行echo 'blabla' | ./test
时,shell将启动echo
进程,并将其标准输出管道连接到./test
的标准输入管道。这与C++无关:这些管道是大多数操作系统的特性,几乎每个进程都有它们。
当您的程序执行system
时,您将创建一个连接到同一标准输入管道的新进程(或多个进程)。因此,如果管道中有一些数据(来自echo
命令)没有被test
读取,则可以通过您使用system
启动的进程读取数据。
使用echo
和管道可以向fgets
和scanf
提供输入。向程序传递数据的另一种方法是使用环境变量或命令行参数,但您需要修改代码来检查这些内容。
https://stackoverflow.com/questions/32336522
复制相似问题