突然ですが、このコードを走らせている途中で in.txtを tail -f とかしたらどうなるでしょう?
$ cat loop.pl
#!/usr/bin/perl use strict; my $i = 0; while(1) { $i++; print STDOUT "hello".$i."\n"; print STDERR "hello-error".$i."\n"; sleep(1); }
$ ./loop.pl > in.txt 2> err.txt
上記を一つのターミナルで走らせて(bg実行でもいいです)、他のターミナルで tail -f in.txt やったら? 何も表示されない。。。 となります。一方 tail -f err.txtは書き込まれます。なぜでしょう?
perlやpython,ruby,PHPは、デフォルトで標準出力をバッファリングしてます。つまりスクリプトの実行が完了するまで、ファイルにフラッシュ出来ません。画面=標準出力に逐一出ているので、納得できませんが、そういうことです。
一方、標準エラーは即時フラッシュしているので、err.txtに書かれるというわけです。 じゃあ、この標準出力のバッファリングを黙らせてやればよいです。
perlの場合
#!/usr/bin/perl use strict; #stop buffering local $| = 1; my $i = 0; while(1) { $i++; print STDOUT "hello".$i."\n"; print STDERR "hello-error".$i."\n"; sleep(1); }
pythonの場合
#!/usr/bin/python import time import sys import os # stop buffering sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) i = 0 while 1: i = i + 1 print u"hello%d" % i sys.stderr.write(u"hello-error%d\n" % i) time.sleep(1)
rubyの場合
#!/usr/bin/ruby # stop buffering STDOUT.sync = true i = 0 loop { i += 1 print "hello" + i.to_s() + "\n" STDERR.print "hello-error" + i.to_s() + "\n" sleep(1); }
やっぱrubyええわ~ 分かりやすい。PHPは自分で調べてね!(PHPでCLIを作る気がしないのと、emacsのflycheck-phpが非力で頼れないので。) スクリプト言語で長時間走る処理の、標準出力を読みたい!終わった後じゃなく途中を!という場合、ちゃんとファイルを開いてログに書けばいいのですが、リダイレクトで何とかしたい、ときにハマりましたので、備忘録として書いておきます。