Linux‎ > ‎

標準出力・標準エラー出力とリダイレクト:基礎


このページは出力リダイレクトの基礎編になります。こちらもあわせてご参照ください。


リダイレクトを使用すると、標準出力の内容をファイルに出力したり、ファイルから標準入力へ入力する事ができます。このページでは、標準出力と標準エラー出力のリダイレクトについて説明します。

リダイレクトは
コマンド > ファイル名
と書くことが多いことから「>の左側のコマンドの出力結果」「>の右側のファイル」に出力する、と解釈している人も少なくないと思います。しかしこの解釈は正確ではありません。このような認識のままだと、標準出力をファイルに出力するパターン以外を正しく理解できず、バグを埋め込む原因にもなりかねません。

リダイレクトの基本的な書式

リダイレクトの基本的な書式は以下だと考えると、多くの事が理解しやすくなります(※ただしこの項は、筆者の独自の解釈を含んでいます)
リダイレクト元 リダイレクト記号 リダイレクト先


リダイレクト元 リダイレクト記号 リダイレクト先
なし (省略時は1と同じ),
1 (標準出力),
2 (標準エラー出力),
n (nは3~9の数字。任意のリダイレクト先)
> (上書き出力),
>> (追加出力)
&1 (現在、標準出力が割当てられているところ),
&2 (現在、標準エラーが割当てられているところ),
&n (nは3~9の数字。割当て済みの任意のリダイレクト先),
ファイル名,
/dev/null (どこにも出力させないとき)

リダイレクト元にはファイルディスクリプタ番号を指定します。ファイル名は書けません。リダイレクト元は基本的には1か2を指定します。1は標準出力、2は標準エラー出力を意味します。省略可能で、省略した場合には1を指定したことになります。任意の番号にファイルディスクリプタ番号を割り当てる場合には、3-9の数字を指定します(0は標準入力です)

一方、リダイレクト先にはファイルディスクリプタ番号もファイル名も書けます。例えば「1」「2」というファイル名も記述可能です。そのためリダイレクト先には、ファイルディスクリプタ番号とファイル名を区別する為に、ファイルディスクリプタ番号の前に「&」を付加する必要があります。「&1」は標準出力(の出力先)、「&2」は標準エラー(の出力先)を意味します。また、画面にもファイルにも出力しない場合には「/dev/null」を指定します。

リダイレクト元は「標準出力」、リダイレクト先には「現在、標準出力が割当てられているところ」と区別して書きました。これは、同じではないことを示しています。「標準出力が割当てられているところ」とは、出力先のポインタの値がコピーされると考えると分かりやすいと思います。

ここまでを頭に入れておけば、下記の2例が同じ意味である事や、
1>result.txt
>result.txt

2>&1
が「標準エラー出力の出力先を標準エラーと同じものにしている」という事が容易に理解できるでしょう。


複数のリダイレクトの記述と記述の位置

リダイレクトの記述は複数記述する事ができます。例えば標準出力と標準エラー出力の両方を同じファイルにリダイレクトする場合は以下のように書きます。
         #1           #2
command 1>result.txt 2>&1 # …(1)

またコマンドの右に書かなければならないということはありません。コマンドの左に書いても意味や結果は同じです。
1>result.txt comannd 2>&1 # …(1-1)
1>result.txt 2>&1 comannd # …(1-2)

(1-1)(1-2)の書き方は「コマンド > ファイル名」の形式で考えていたら理解不可能な書き方ですね。実際にはリダイレクトの記述は慣例的にコマンドの右側に記述する事がほとんどです。その為、コマンドの左側に書くと混乱してしまう人がでてきかねないので、特別な理由でもない限りはコマンドの右側に書くようにしましょう。しかし、どこに書こうと文法的に正しいという事は知っておくべきだと思います。

評価の順番

リダイレクトの記述を複数記述した場合には、左から順番に評価します。「1>result.txt」と「2>&1」の記述順序を変えて(間違えて)以下のように書いた場合、
         #1    #2
comannd 2>&1 1>result.txt # …(2)
一見同じように思えますが、実際には結果が変わります。

(1)は、標準出力の出力先をファイルにし、「標準エラーの出力先を、現在標準出力の出力先に割り当てられている場所=ファイル」にする、という意味です。(2)は、「標準エラーの出力先を、現在標準出力の出力先に割り当てられている場所=画面」にし、標準出力の出力先をファイルにする、という意味になります。

(1)のケースの出力先は以下のように遷移します。
No. 処理 1番(STDOUT) 2番(STDERR) 備考
#0 初期状態 画面 画面 -
#1 1>result.txt ファイル 画面 1番の出力先をファイルに変更
#2 2>&1 ファイル ファイル 2番の出力先を1番と同じ(ファイル)にする


(2)のケースの出力先は以下のように遷移します。
No. 処理 1番(STDOUT) 2番(STDERR) 備考
#0 初期状態 画面 画面 -
#1 2>&1 画面 画面 2番の出力先を1番と同じ(画面)にする。何も変わらない!
#2 1>result.txt ファイル 画面 1番の出力先をファイルに変更

つまり(1)は、標準出力・標準エラー出力ともにファイルに出力されます。しかし(2)は、標準出力はファイルに出力され、標準エラー出力は画面に出力されます(よくある失敗例です)。記述順が結果に影響する事を把握し、きちんと考えてコーディングする事が大切です。


また、パイプ記号で「|」次のコマンドに標準出力を渡す場合には、リダイレクションによる処理に優先して処理されます。

例えば以下の例の場合、
          #2  #1
comannd1 2>&1 | comannd2 # …(3)
左から順に評価すると考えると、「2>&1」は無意味で単にcomannd1の実行結果の標準出力をcomannd2に渡しているだけのように見えます。しかし実際には、標準出力・標準エラー出力の両方がcomannd2に渡されます。

出力先は以下のように遷移します。
No. 処理 1番(STDOUT) 2番(STDERR) 備考
#0 初期状態 画面 画面 -
#1 | 次のコマンド 画面 1番の出力先をファイルに変更
#2 2>&1 次のコマンド 次のコマンド 2番の出力先を1番と同じ(次のコマンド)にする
パイプが優先的に評価されるという事も念頭においてコーディングをするようにしましょう。


2012/10/27