リダイレクトを理解する

ALL
スポンサーリンク

bash でリダイレクトを書く際、時々迷います。
例えば、標準出力も標準エラー出力もファイルに出力したい場合、
「コマンド > output.txt 2>&1」と
「コマンド 2>&1 > output.txt 」、
どちらが正しい書き方でしょうか?

正解は「コマンド > output.txt 2>&1」です。

このリダイレクトの書き方についてです。

スポンサーリンク

前提

ここで次のルールを前提とします。

  1. リダイレクトで出てくる 1 や 2 の数字はファイル識別子で、1 は標準出力、2 は標準エラー出力を示す
  2. 標準出力、標準エラー出力はデフォルトではコンソール(画面)である
  3. リダイレクトで単に > と表記したら、1> を示す
  4. リダイレクト先がファイル識別子の場合は、>& を使う
  5. リダイレクトの評価(処理)は、左から右に向かって行われる

これを前提に、
「コマンド > output.txt 2>&1」と
「コマンド 2>&1 > output.txt 」の動作を考えてみます。

「コマンド > output.txt 2>&1」の場合

コマンド > output.txt 2>&1

ルール5より、「2>&1」より先に「> output.txt」を評価(処理)します。
ルール3より、「> output.txt」は「1> output.txt」と等価です。
ルール1より、1は標準出力です。
つまり、「> output.txt」は標準出力先をファイル output.txt にしています。

コマンド > output.txt 2>&1

ルール1より、1は標準出力、2 は標準エラー出力です。
ルール4より、リダイレクト先がファイル識別子 1なので > では無く >& を使っています。
つまり、「2>&1」は標準エラー出力を標準出力にしています。
ここで、標準出力先は、先述の「> output.tx」でファイル output.txt になっているので、結果的に標準エラー出力は output.txt になります。

「コマンド 2>&1 > output.txt」の場合

コマンド 2>&1 > output.txt 

ルール5より、「> output.txt」より先に「2>&1」を評価(処理)します。
ルール1より、1は標準出力、2 は標準エラー出力です。
ルール4より、リダイレクト先がファイル識別子 1なので > では無く >& を使っています。
つまり、「2>&1」は標準エラー出力を標準出力にしています。
ルール2より、この時点では、標準出力先はデフォルトのコンソール(画面)です。
従って、標準エラー出力先はコンソールに設定されます。

コマンド 2>&1 > output.txt

ルール3より、「> output.txt」は「1> output.txt」と等価です。
ルール1より、1は標準出力です。
つまり、「> output.txt」は標準出力先をファイル output.txt にしています。
標準エラー出力先は、先述の「2>&1」を評価(処理)時点で、コンソールに設定されており、変わりません。

従って、標準出力=output.txt、標準エラー出力=コンソール になります。
このように、標準出力も標準エラー出力もファイルにしたくとも、意図通りになりません。

以上、bash でのリダイレクトの書き方でした。

参考

linux – cmd 2>&1 > log vs cmd > log 2>&1 – Stack Overflow
shell – What does "3>&1 1>&2 2>&3" do in a script? – Unix & Linux Stack Exchange
【linux】0.stdin 標準入力、1.stdout 標準出力、2.stderr 標準エラー at softelメモ
bash – In the shell, what does " 2>&1 " mean? – Stack Overflow

コメント