リダイレクトとパイプを図示してみた (2)

前回の続きです。今回は、リダイレクトの記号が複数のケースと、パイプを使うケースを説明します。
前回: id:simply-k:20100731:1280607841
次回: id:simply-k:20100802:1280617927

(7) コマンド 1> ファイル 2>&1

2段階に分割して考えます。リダイレクトの記号が複数の場合は、左側から順に考えます。

(7-1) 1> ファイル


1番の出力先(標準出力)をファイルにリダイレクトします。内部的には、ファイルを書き込み用にオープンし、その出力ストリームを1番に結び付けます。*1

(7-2) 2>&1


2番の出力先(標準エラー出力)を1番の出力先(ファイル)にリダイレクトします。内部的には、1番に結びつけられたストリーム(file)を2番に結び付けます。リダイレクトしない場合に標準出力と標準エラー出力に分かれて出力されるデータが、同じファイルに出力されることになります。
なお、標準出力と標準エラー出力をそれぞれ同じファイルにリダイレクトするからといって、「コマンド 1> ファイル 2> ファイル」と書くことは一般にはできません。実行環境によりますが、同じファイルを書き込みモードで2重にオープンしようとしてエラーが発生したり、標準出力のデータが標準エラー出力のデータで上書きされてしまったりします。*2

(8) コマンド 2> ファイル 1>&2

2段階に分割して考えます。リダイレクトの記号が複数の場合は、左側から順に考えます。

(8-1) 2> ファイル


2番の出力先(標準エラー出力)をファイルにリダイレクトします。内部的には、ファイルを書き込み用にオープンし、その出力ストリームを2番に結び付けます。*3

(8-2) 1>&2


1番の出力先(標準出力)を2番の出力先(ファイル)にリダイレクトします。内部的には、2番に結びつけられたストリーム(file)を1番に結び付けます。リダイレクトしない場合に標準出力と標準エラー出力に分かれて出力されるデータが、同じファイルに出力されることになります。
(7)の「コマンド 1> ファイル 2>&1」と(8)の「コマンド 2> ファイル 1>&2」は、結果的に同じ処理となります。

(9) コマンド 2>&1 1> ファイル

2段階に分割して考えます。リダイレクトの記号が複数の場合は、左側から順に考えます。

(9-1) 2>&1


2番の出力先(標準エラー出力)を1番の出力先(標準出力)にリダイレクトします。内部的には、1番に結びつけられたストリーム(stdout)を2番に結び付けます。*4

(9-2) 1> ファイル


1番の出力先(標準出力)をファイルにリダイレクトします。内部的には、ファイルを書き込み用にオープンし、その出力ストリームを1番に結び付けます。2番に結び付けられたストリームは変更されません。標準エラー出力に出力されるはずだったデータが標準出力に出力され、標準出力に出力されるはずだったデータがファイルに出力されます。
(9)は、(7)のリダイレクトの順序を入れ替えたものです。図を見てわかるように、(7)と(9)では出力先が異なります。このように、リダイレクトの指定順序によって出力先が変わる場合があるので、注意が必要です。

(10) コマンドA | コマンドB

2段階に分割して考えます。

(10-1) コマンドA、コマンドB



コマンドAとコマンドBを単独実行する場合です。各コマンドのストリームを区別するため、ストリーム名に「-a」または「-b」を付けています。

(10-2) コマンドA | コマンドB


コマンドAとコマンドBが、パイプによって接続されます。コマンドAの標準出力(stdout-a)とコマンドBの標準入力(stdin-b)が1つになったかのように動作します。内部的には、以下の処理が行われます。

  • コマンドA側
    1. パイプを書き込み用にオープンする。
    2. 標準出力(stdout-a)の代わりにパイプが使われるように、ストリームの結びつきを変更する。
  • コマンドB側
    1. パイプを読み込み用にオープンする。
    2. 標準入力(stdin-b)の代わりにパイプが使われるように、ストリームの結びつきを変更する。

なお、厳密には「パイプ」、「パイプへの出力ストリーム」、「パイプからの入力ストリーム」の3つは別々に描くべきですが、図の簡略化のため、1つにまとめて「pipe」としています。


(11)以降は次回です。
前回: id:simply-k:20100731:1280607841
次回: id:simply-k:20100802:1280617927

*1:前回の記事の(3)と同じ状態になります。

*2:「foo 1> nul 2> nul」や「foo 1> /dev/null 2> /dev/null」のように大丈夫な場合もあります。

*3:前回の記事の(4)と同じ状態になります。

*4:前回の記事の(6)と同じ状態になります。