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);
}

私とパイプなしで実行すると、正常に動作し、shpromtを返します。

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$

これは、EOFを受信し、エラーメッセージなしですぐに終了するような方法でgets空になるという事実と関係があると思います。stdin/bin/sh

getsしかし、パイプを介して入力を供給してもpromtを取得できるように、(可能であればプログラムを変更せずに、そうでない場合は削除せずに)これを回避するにはどうすればよいですか?

PS私はこれをFreeBSD(4.8)マシンDSで実行しています

4

3 に答える 3

10

次のような変更を加えずにプログラムを実行できます。

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

このようにして、プログラムの標準入力が出力後に終了しないようにしechoます。代わりに、catプログラムに入力を提供し続けます。これがcat読み取り元であるため、後続の入力のソースは端末です。

セッションの例を次に示します。

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$

シェルの標準入力は端末に接続されてshいないため、インタラクティブに実行されていないと見なされ、プロンプトが表示されないことに注意してください。ただし、コマンドは通常どおり入力できます。

于 2011-12-14T18:02:14.750 に答える
3

使用するexecve("/bin/sh", 0, 0);ことは、シェルに対する残酷で異常な罰です。引数や環境はまったく与えられません。それ自体のプログラム名も、PATHやHOMEなどの必須の環境変数も与えられません。

于 2011-12-14T18:02:32.633 に答える
1

これを100%確信しているわけではありません(使用されている正確なシェルとOSがこれらの答えを少し投げる可能性があります。FreeBSDはbashデフォルトでGNUを/bin/sh?として使用していると思います)。

  • shその入力がttyではないことを検出している可能性があります。

また

  • お使いのバージョンは、として呼び出さshれた場合にも、そのような非対話型モードになる可能性があります。設定すると、ログインシェルとして実行されていることを納得させることができます。shlogin-argv[0]execve ("/bin/sh", { "-sh", NULL}, NULL)
于 2011-12-14T17:58:52.127 に答える