- 締切済み
パイプってどうやって使うの?
1つ目のプログラムの出力を2つ目のプログラムで受け取りたいのですが、どうすればいいですか? -- 1 -- #include <stdio.h> #include <windows.h> int main(void){ int a=0; while(1){ fprintf(stdout,"%d\n",a++); Sleep(1000); } return 0; } これを2のプログラムで受け取ります。 #include <stdio.h> int main(void){ char str[128]; while(1){ if(fgets(str,sizeof(str),stdin)==NULL) break; printf("%s",str); } return 0; } これをコマンドプロンプトで 1 | 2 と入力してみましたが、何も表示されません・・。 個別に実行すると正常に動作します。 環境はXPです。どうしたら受け渡しが出来るのでしょうか?
- みんなの回答 (7)
- 専門家の回答
みんなの回答
- Tacosan
- ベストアンサー率23% (3656/15482)
ところで, 2 の方が「入力に依存せずに終了する」(例えば while ループじゃなくて「1回読み込んだから終了」) 場合に, コマンドプロンプトまで戻らないような感じもするんだけど気のせいかなぁ? UNIX なら SIGPIPE で止まるところが止まっていない感じ. Vista でそんな風になったんだけど, 何か間違えたのかなぁ....
XPのcommand.comとcmd.exeでもそんな実装にはなっていないことを補足させてもらいます setvbufかfflushだけで問題有りません >コマンドプロンプトで1|2とやってパイプラインを動かしたままにして、タスクマネージャーで「実行中のアプリケーション」や「実行中のタスク」を見てみましょう。 2.exeが存在することを実際に確認しました >「本当に2が起動されないままなのか確かめたい」のなら「2の先頭に、無条件に何かを表示するprintfを入れてみる」と良いでしょう。 1.exeがループ中に2.exeから出力されることを実際に確認しました
- Tacosan
- ベストアンサー率23% (3656/15482)
蛇足: #4 では「command.com ではそのようにパイプを実装してる」と書いたものの, 試してみたら (少なくとも) Vista では command.com でもまともなパイプの動作をしてるよ.... ということで, その部分は無視してほしい.
- Tacosan
- ベストアンサー率23% (3656/15482)
XP では試してないけど Vista なら #1 でちゃんと動く. 少なくとも Vista では実際に試した結果だから間違いない. 確かに command.com ではそのようにパイプを実装してるけど>#2, MS-DOS や 16ビットの Windows ならいざ知らずカーネルオブジェクトとしてパイプが存在する 32ビット Windows で (しかも 32ビット Windows のコマンドシェルである cmd.exe で) そんなしょぼい実装をするかねぇ. いくら Microsoft といえど.
- sakusaker7
- ベストアンサー率62% (800/1280)
少なくとも「コマンドプロンプト」が動くようなwindowsであれば、 まともなパイプが使えるようになってます。 たとえば、unixにあるようなyesコマンドとheadコマンドを組み合わせて yes|head としてもちゃんと終了します。 ですので、#1のTacosanさんの見るように バッファにたまってるだけの話だと思います。
- chie65536(@chie65535)
- ベストアンサー率44% (8740/19838)
>これをコマンドプロンプトで >1 | 2 >と入力してみましたが、何も表示されません・・。 そりゃそうです。 Windowsのコマンドプロンプトでは「1」が正常終了しない限り「2」は実行されません。 言い換えれば「2が実行されるのは、1が正常終了したときだけ」です。 コマンドプロンプトで 1|2 とやってパイプラインを動かしたままにして、タスクマネージャーで「実行中のアプリケーション」や「実行中のタスク」を見てみましょう。 アプリケーションやタスクには「1.exe」はありますが「2.exe」は無い筈です。 ご質問のパターンでは「1は強制終了して止めるしかない」ので 1|2 のパイプラインを実行した場合「2が起動される事は永遠に無い」です。 パイプラインを実行する環境がUNIXやLinuxなどのシェル(shやcsh)であれば、シェルがマルチプロセス起動に対応しているので 1|2 とパイプで繋ぐと1と2は同時に起動され、1の中から呼ぶSleepやシステムコールにより2に制御が移り、1と2が交互に動作し、正しく表示されます。 しかし、Windowsのコマンドプロンプトでは「1」が正常終了しない限り「2」は実行されませんので 1|2 とパイプで繋ぐと1だけ起動し、永久ループします。 1を止めるには、コマンドプロンプトウィンドゥの右上隅の[×]ボタンで「コマンドプロンプトウィンドゥごと強制終了する」しかありません。 なお「MS-DOS」や「Windowsのコマンドプロンプト」では 1|2 と実行するのは 1 > tempfile.$$$ 2 < tempfile.$$$ del tempfile.$$$ と書かれたバッチファイルを動かすのと同等です。 このバッチファイルは 1 > tempfile.$$$ が終了しない限り 2 < tempfile.$$$ の行は実行しません。 これからも判る通り「Windowsのコマンドプロンプトでは、パイプコマンドの中に無限ループして終了しないプログラムがあると、それより右に書いたプログラムは起動されない」です。 「2が起動される事はない」のですから、1の中でsetbuf(stdout, NULL);してバッファリグしないようにしたりfprintfのあとでfflush(stdout);をしようが、すべては無駄です。徒労に終ります。 「本当に2が起動されないままなのか確かめたい」のなら「2の先頭に、無条件に何かを表示するprintfを入れてみる」と良いでしょう。 「無限ループして終了しないプログラムをパイプラインで繋いで、ちゃんと表示させたい」のなら「Windowsでは不可能」なので、今すぐCドライブをフォーマットしてWindowsを全部消し、FreeBSDなど、Unix系のOSを導入しましょう。
- Tacosan
- ベストアンサー率23% (3656/15482)
手元で実験してみたけど, 1 の方で書きだすときにバッファリングしてるため, 十分なデータがたまらないと 2 で読み込めなくなってる. だから Sleep しなければちゃんと出力されるし, Sleep しても最初に setbuf(stdout, NULL); でバッファリグしないようにしたり fprintf のあとで fflush(stdout); によりフラッシュすればちゃんと出力できる.