10

我有以下示例程序:

#include <stdio.h>

int
main(int argc, char ** argv){
    char buf[100];

    printf("Please enter your name: ");
    fflush(stdout);
    gets(buf);
    printf("Hello \"%s\"\n", buf);

    execve("/bin/sh", 0, 0);
}

我和当我在没有任何管道的情况下运行时,它会正常工作并返回一个sh提示:

bash$ ./a.out
Please enter your name: warning: this program uses gets() which is unsafe.
testName
Hello "testName"
$ exit
bash$

但这在管道中不起作用,我想我知道为什么会这样,但我无法找到解决方案。示例运行如下。

bash$ echo -e "testName\npwd" | ./a.out
Please enter your name: warning: this program uses gets() which is unsafe.
Hello "testName"
bash$

我认为这与这样一个事实有关,即以这种方式gets清空接收 EOF 并在没有错误消息的情况下立即退出。stdin/bin/sh

但是我该如何解决这个问题(如果可能,不修改程序,如果不删除,则不删除gets),以便即使我通过管道提供输入,我也会得到提示?

PS 我在 FreeBSD (4.8) 机器 DS 上运行它

4

3 回答 3

10

You can run your program without any modifications like this:

(echo -e 'testName\n'; cat ) | ./a.out

This way you ensure that your program's standard input doesn't end after what echo outputs. Instead, cat continues to supply input to your program. The source of that subsequent input is your terminal since this is where cat reads from.

Here's an example session:

bash-3.2$ cc stdin_shell.c 
bash-3.2$ (echo -e 'testName\n'; cat ) | ./a.out 
Please enter your name: warning: this program uses gets(), which is unsafe.
Hello "testName"
pwd
/home/user/stackoverflow/stdin_shell_question
ls -l
total 32
-rwxr-xr-x  1 user  group  9024 Dec 14 18:53 a.out
-rw-r--r--  1 user  group   216 Dec 14 18:52 stdin_shell.c
ps -p $$
  PID TTY           TIME CMD
93759 ttys000    0:00.01 (sh)
exit

bash-3.2$

Note that because shell's standard input is not connected to a terminal, sh thinks it is not executed interactively and hence does not display the prompt. You can type your commands normally, though.

于 2011-12-14T18:02:14.750 回答
3

Using execve("/bin/sh", 0, 0); is cruel and unusual punishment for the shell. It gives it no arguments or environment at all - not even its own program name, nor even such mandatory environment variables as PATH or HOME.

于 2011-12-14T18:02:32.633 回答
1

不是 100% 确定这一点(使用的精确 shell 和操作系统可能会抛出这些答案;我相信 FreeBSDbash默认使用 GNU 作为/bin/sh?),但是

  • sh可能正在检测其输入不是 tty。

或者

  • 如果调用 as ,您的版本可能会进入sh非交互模式sh,期待login会为它添加一个。设置可能会说服它作为登录 shell 运行。-argv[0]execve ("/bin/sh", { "-sh", NULL}, NULL)
于 2011-12-14T17:58:52.127 回答