Go to list of users who liked
Share on X(Twitter)
Share on Facebook
More than 5 years have passed since last update.
パイプ処理における問題といえば、例のcat file | while readの同一変数が別コンテキストになる問題でしょ?と思われたかもしれないですが、それとはまた別のお話でして。
seq1 1000 |head-10上記のコードを実行すると、画面上には1~10が表示されます。
パイプ前段のプロセスが無限に標準出力する場合でも、パイプ後段のプロセスが必要な結果だけ取得できれば事足りるので、前段プロセスが愚直に最後まで計算を続けたりする必要はない。これはかしこい。
for((i=0;;i++)){# 終了条件が無いが無限ループにならないbuiltin echo"i=$i"} |head-10ただ、このようなイケてる遅延評価があだとなり、結果的に、ユーザの思惑に反する挙動をしてしまうケースもあります。
例えば以下のコードの場合、書かれてある通りに解釈すれば、本来ファイルにはi=99まで出力されてしかるべきなんですが、実行してみるとi=15までしか出力されませんでした。
i=16を書き込もうとしたタイミングで、書き込もうとしたパイプが後段プロセスによってクローズ済みだったため、SIGPIPEが発生したというところでしょうか。
rm-f ./sample.logfor((i=0; i<100; i++)){builtin echo"i=$i"builtin echo"i=$i">>./sample.log} |head-10$cat ./sample.logi=0i=1i=2...i=14i=15 #i=99まで出力されるべきが、i=15の直後でSIGPIPE発生$試しに、以下のようなseq2コマンド(SIGPIPEを受信したタイミングでメッセージをエラー出力する)を実装し、パイプにつなげてみました。
# include <stdio.h># include <stdlib.h># include <signal.h>voidcatch(intsignum){signal(SIGPIPE,SIG_IGN);fprintf(stderr,"**** signal(%d) is received !!! ****\n",signum);exit(1);}intmain(intargc,char**argv){signal(SIGPIPE,catch);if(argc<4)exit(1);longstart=atol(argv[1]);longend=atol(argv[2]);longstep=atol(argv[3]);for(longi=start;i<=end;i+=step)printf("%ld\n",i);printf("**** end ****\n");return0;}以下が実行結果です。確かに、SIGPIPEが発生しています。
$./seq2 1 2147483647 1 |head-1012345678910**** signal(13) is received !!! ****これ知らないと、ハマりそうですね。パイプはあくまで「I/Oを一方向につなげて多段フィルタをかける」ためのもので、並列処理だぜヒャッホー!ってなノリで使っちゃ危険ということですね。
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme