-
Notifications
You must be signed in to change notification settings - Fork 10
ptwコマンド
英語版はこちら(English document is here.)
- 次のファイルをダウンロードせよ。
https://github.com/ShellShoccar-jpn/misc-tools/blob/master/C_SRC/ptw.c、またはダイレクトリンク
- それを次のようにコンパイルせよ。
$ cc -O3 -o ptw ptw.c
これにより、ptw(疑似端末ラッパー)というコマンドが生成される。
- 次のコードを実行し、比べてみることにより、ptwが正しく動作することを確かめてみよ。
# stdbufを使う場合(最後に一気に表示、つまり失敗する)
$ (i=0; while [ $i -lt 2 ]; do echo $i; sleep 1; i=$((i+1)); done; echo $i) | stdbuf -o L perl -pe 's///' | cat
# ptwを使う場合(1秒間隔で表示、つまり成功する)
$ (i=0; while [ $i -lt 2 ]; do echo $i; sleep 1; i=$((i+1)); done; echo $i) | ./ptw perl -pe 's///' | cat
stdbufの効かないコマンドの多くは自分自身でバッファリングモードを管理しています。そしてそれらのほとんどは、バッファリングモードをユーザーが変更できるようになっています。例をいくつか示します。
- Perl
- Perlをラインバッファリングモードで動かしたい場合は、組み込み変数"
$|
"に1を代入します。
- Perlをラインバッファリングモードで動かしたい場合は、組み込み変数"
- Python
- "
-u
"オプション付きでpythonを起動すると、バッファリングを完全にしなくなります。
- "
stdbufコマンドがバッファリングモードを切り替えるタイミングは、対象コマンドの起動前です。つまり、stdbufはまずバッファリングモードを切り替えてからコマンドを起動します。したがって、もしターゲットコマンドが起動した後で独自にバッファリングモードを初期化すると、stdbufが設定したものは上書きされてしまいます。
標準入出力ライブラリー<stdio.h>に収録されている標準出力へ書き出す各種関数は、そのライブラリーをインクルードしたコマンドがパイプラインの開始端や途中にあるか、あるいは終端にあるかでデフォルトの動作を替えます。前者の場合はフルバッファリングモード、後者の場合はラインバッファリングモードになります。そしてバッファリングモードを自己管理しているコマンドの多くも、この慣習に従います。
そこでptwコマンドは、疑似ターミナル(PTY)を使ってターゲットコマンドを騙します。 まずptwは、標準出力に接続されたPTYを作成し、次にターゲットコマンド用の標準出力をPTYにすり替え、ターゲットコマンドを起動します。 ターゲットコマンドは、自分に与えられた標準出力がターミナルのように見えるため、自分がパイプラインの最後にあると思い込みます。 その結果、そのコマンドはラインバッファリングモードでデータを送信します。 これがptwのメカニズムです。
このコマンドをもってしても、次のようなコマンドには効果がありません。
- <stdio.h>ライブラリーを使用していないコマンド。そもそもptwは、<stdio.h>やそれに類する動作をするバッファーの習性を逆手に取って騙すという動作原理をとるからです。
- <stdio.h>ライブラリーを使用してはいるが、自分がパイプラインのどこに配置されているのかを気にせず、常にフルバッファリングモードにするコマンド。mawkなどがその例で、これは"
-W interactive
"というオプションが与えられない限り、常にフルバッファリングモードで動作します。