なぜ stdout の出力結果は混じらないのか
stdout は、一見単一のファイルに見える。しかし端末を複数開いている時、それぞれの端末の出力が混線することはない。なぜか。
$ ls /dev/stdout
/dev/stdout
stdout は /dev/stdout に仮想ファイルとして存在している。
このファイルを読んでいるのだから混線しそうなものだが、実際には混線することはない。
さてこの /dev/stdout の詳細を追ってみよう。
$ ll /dev/stdout lrwxrwxrwx 1 root root 15 Oct 2 00:24 /dev/stdout -> /proc/self/fd/1
/dev/stdout は /proc/self/fd/1 へのシンボリックリンクになっている。/proc/self は現在実行中のプロセスへのリンクを保持するディレクトリである。つまりプロセスごとに /proc/self ディレクトリのリンク先は異なっているわけだ。
本当に異なっているか、見てみよう。
$ ll /proc/self lrwxrwxrwx 1 root root 64 Oct 2 00:23 /proc/self -> 9159/ $ ll /proc/self lrwxrwxrwx 1 root root 64 Oct 2 00:23 /proc/self -> 9167/
確かに、コマンド毎にリンク先が異なっている。最初の ll コマンドの時のリンク先は /proc/9159, 二度目の ll コマンドの時のリンク先は /proc/9167 だ。
改めて、/proc/self/fd/1 は何を表しているのか見てみよう。
まず /proc/self は /proc/$PID だったので、/dev/stdout は /proc/$PID/fd/1 へのリンクだということになる。
では /proc/$PID/fd ディレクトリは何を表すディレクトリなのか。これは、このプロセスがオープンしているファイルディスクリプタを保持するディレクトリである。とはいえ stdout は常にファイルディスクリプタ1番で表されるので、当該プロセスが1番をオープンしているかどうかは関係なく、常に存在する。/proc/$PID/fd/$fd は当該ファイルへのシンボリックリンクになっており、リンクを辿ることでどのファイルをオープンしているのか知ることができる。
$ ll /proc/self/fd/1 lrwx------ 1 aoking aoking 64 Oct 2 04:07 /proc/self/fd/1 -> /dev/pts/3
上記のシェルからでは /dev/pts/3 にリンクされていた。別のシェルから叩いてみよう。
$ ll /proc/self/fd/1 lrwx------ 1 aoking aoking 64 Oct 2 04:08 /proc/self/fd/1 -> /dev/pts/4
というわけで、「なぜ stdout の出力は混じらないのか」という問に対しては、「シェル毎に /proc/self/fd/1 のリンク先が異なっているから」というのが答えになります。
では /proc/self/fd/1 のリンク先の /dev/pts/3 や /dev/pts/4 はなんなのでしょう?これは擬似端末と呼ばれる仮想デバイスで、実際の画面(モニタ)の解像度や色などに関わらず端末が抽象化されたスペシャルファイル。今自分のシェルがどの仮想端末を用いているかは、tty コマンドで知ることができる。
$ tty
/dev/pts/3
別のシェルからだと別の結果に。
$ tty
/dev/pts/4
ll /proc/self/fd/1 した時のリンク先を表示してるだけですね。
さてこの /dev/pts/3 や /dev/pts/4 に対して読み書きできるので、こんな遊びもできます。
$ tty /dev/pts/3 $ echo hello > /dev/pts/4
こうすると、このシェルでは何も表示されないが、/dev/pts/4 と結びついている端末を開くと、あら不思議。
$ hello
と、さっきのコマンドの出力結果が表示されている。
なんとも悪用への知恵が働きそうなシロモノです。
- 作者: Daniel P. Bovet,Marco Cesati,高橋浩和,杉田由美子,清水正明,高杉昌督,平松雅巳,安井隆宏
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2007/02/26
- メディア: 大型本
- 購入: 9人 クリック: 269回
- この商品を含むブログ (67件) を見る