【问题标题】:What exactly happens when I use '|' or '<', c++当我使用“|”时究竟会发生什么或'<',c++
【发布时间】:2023-04-01 03:32:02
【问题描述】:

我有一个非常简单的程序:

void main()
{
    fgets(buf,133,stdin);
    printf( buf);
    system("/bin/dash");
}

当我启动程序时,一切正常,我可以输入我想要的任何内容,然后我就有了一个 shell。但是,如果我这样做了

$ echo 'blabla' | ./test

为了自动填充 buf(无需使用键盘输入任何内容),shell 会被执行,但 /bin/ls 可以正常工作。 (显然显示命令工作正常)

如果我删除 fgets 行,并执行相同的命令,它可以工作,但将 'blabla' 作为 /bin/dash 的参数。但是,添加一个 nul 字符或返回 '\xd' 以模拟我的键盘在 fgets 中的返回不起作用

我想了解当我使用“|”时会发生什么我的 C++ 程序中的符号。我认为这是无需任何人工交互即可自动填充 scanfs 和 fgets 的解决方案,是我做错了还是有其他解决方案?

谢谢。

Debian,C++ g++

【问题讨论】:

  • 在标准 C++ 中 main 总是返回一个 int
  • void main() 错误
  • 你的cmets安静没用
  • 关于XY问题的评论其实很有用。我很难回答,因为我不确定您的目标是什么,所以我不知道您在问题中指的是哪种“解决方案”。相反,我只是回答了您的第一个问题,即使用管道时究竟会发生什么。最好先确切地说出您想要完成的问题,然后描述您尝试过的内容以及尝试中遇到的问题。

标签: c++ linux bash shell


【解决方案1】:

当您在 shell 中执行echo 'blabla' | ./test 时,shell 将启动一个echo 进程并将其标准输出管道连接到./test 的标准输入管道。这与 C++ 无关:这些管道是大多数操作系统的一个特性,几乎每个进程都有它们。

当您的程序执行system 时,您正在创建一个连接到same 标准输入管道的新进程(或多个进程)。因此,如果该管道中有一些数据(来自echo 命令)未被test 读取,那么您使用system 启动的进程将可以读取这些数据。

使用echo 和管道是向fgetsscanf 提供输入的好方法。将数据传递给程序的另一种方法是使用环境变量或命令行参数,但您需要修改代码以检查这些内容。

【讨论】:

  • 我知道 pipe 与 c++ 无关,我只想为任何语言自动填充 scanf,但我想举一个具体的例子。感谢您的解释,但目标是自动填充不是我编写的程序的 scanf,因此不能使用环境和修改代码。
【解决方案2】:

如果我对您的理解正确,您希望同时向您的 fgets 和您的 shell 提供输入,但发现当您通过管道传输时 shell 没有收到任何输入。

这是因为 libc 将为fgets 缓冲输入数据。

不是读取blabla\n 中的 7 个字节并将其余字节传递给 shell,而是读取最多 4096 个字节(取决于系统)并将剩余的 4089 个字节用于将来对标准输入的fgets/f* 调用。这些数据将存储在您的程序内部,并且不可用于从底层流读取的其他进程,例如调用的 shell。

当您以交互方式运行并在键盘上键入时,只有 7 个字节 回车时可用,因此缓冲区仅填充 7 个字节。因此,您键入的其余数据可供 shell 使用。您可以在有问题的程序中模拟相同的效果,并在输入中策略性地放置延迟:

{ 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

【讨论】:

  • 非常感谢!问题是,我想自动完成不是我写的程序,所以我不能使用 setvbuf,但是谢谢你教我 fgets 是如何工作的。我试着像你说的那样睡觉,它奏效了。
  • 耶!但是,如果您尝试自动输入无法修改的二进制文件,我建议您发布一个新问题,说明您想要自动输入无法修改的二进制文件。这样你会得到更优雅、更可靠的答案。
猜你喜欢
  • 2023-03-29
  • 2012-06-06
  • 1970-01-01
  • 1970-01-01
  • 2013-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多