bash でリダイレクトを書く際、時々迷います。
例えば、標準出力も標準エラー出力もファイルに出力したい場合、
「コマンド > output.txt 2>&1」と
「コマンド 2>&1 > output.txt 」、
どちらが正しい書き方でしょうか?
正解は「コマンド > output.txt 2>&1」です。
このリダイレクトの書き方についてです。
前提
ここで次のルールを前提とします。
- リダイレクトで出てくる 1 や 2 の数字はファイル識別子で、1 は標準出力、2 は標準エラー出力を示す
- 標準出力、標準エラー出力はデフォルトではコンソール(画面)である
- リダイレクトで単に > と表記したら、1> を示す
- リダイレクト先がファイル識別子の場合は、>& を使う
- リダイレクトの評価(処理)は、左から右に向かって行われる
これを前提に、
「コマンド > 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
コメント