はじめに
標準出力、標準エラー出力をどちらも破棄したい場合、よく>/dev/null 2>&1
という書き方をすると思います。これを間違えて2>&1 >/dev/null
と書いてうまく動かなかったのですが、いまいち腑に落ちなかったので記法を詳しく調べてみました。
まず前提知識
ハマったポイントに進む前に、いくつか前提知識を整理します。下記のサイトを参考にさせていただきました。
- ファイルディスクリプタについて理解する
- リダイレクト コマンドの出力をファイルや別のコマンドに振り分ける (リダイレクション)
- 紛らわしいけど重大な違いを引き起こすリダイレクトAdd Starblp1526
- いい加減、>/dev/null 2>&1と書くのをやめたらどうか (追記あり)
ファイルディスクリプタ
まず2>
や2>&1
の数字について。これらの数字は、入出力インターフェースにつけられた識別番号で、ファイルディスクリプタというそうです。それぞれ下記のようになっています。
インタフェース | ファイルディスクリプタ |
---|---|
標準入力 | 0 |
標準出力 | 1 |
標準エラー出力 | 2 |
リダイレクト
次に、>
の記号について。>
に続けてパスを指定することをリダイレクトといい、>
以左のコマンドの実行結果の出力先を任意のパスに設定することができます。記法としては下記の通り。
command N>path
ただし、N
は上述のファイルディスクリプタ、command
は任意のコマンド、path
は出力先のパス。ファイルディスクリプタで指定したインターフェースの出力を、path
に指定したファイルに出力することができます。
ちなみに、>
とは1>
の省略形とみなされるため、冒頭の>/dev/null
は標準出力を/dev/null
に設定することを意味します。
※/dev/null
について
リダイレクト時に、どのファイルにも書き出さず、画面にも表示せず、破棄したいときに指定する特殊なパス。/dev/null
というファイルが存在しているわけではありません。
標準出力と標準エラー出力を同じに設定する
最後に、&
の記号について。ファイルディスクリプタの前に&
をつけると、「ファイルディスクリプタで指定したインターフェースに現在設定されている出力先」を表すようになります。たとえば、&1
とすると標準出力(1)に設定されている出力先を表すようになります。
たとえば、command 2>&1
のように指定することで、標準エラー出力(2)の出力先を標準出力(1)の出力先に設定することができます。
ハマりポイント
勘違いの原因
今回2>&1 >/dev/null
と記載して問題に気づけなかった原因は、>
記号が矢印のように見えるためか、command > file
の記載に対し、「command
の出力をfile
につなげる」というイメージを持っていたためでした(パイプ|
と同じような動きをすると勘違いしていた)。また、&1
の表記についても、リダイレクト先に記載するときは&
をつけなきゃいけないんだなーくらいの認識でした。
このイメージをもって、下記の記載(誤りです)を見てみると、確かに、「command
の出力について、標準エラー出力を標準出力につなげ、さらにまとめて/dev/null
に捨てる」...なんだかよさそうに見えてしまいます。
command 2>&1 >/dev/null
しかし実際のところ、N>file
は「N
の出力先をfile
に設定する」という意味合いですし、「&N
は現在N
に設定されている出力先」のことです。ここまで理解したうえで、再度上記の誤った記載を見直してみると、下記のように、まったくトンチンカンなことをしていることに気づきます。2>&1
の時点では、まだ標準出力の出力先は画面なので、2>&1
をしても何も起きません。
- 標準エラー出力の出力先を、標準出力に設定されているパス(ここではまだ画面)に設定する(
2>&1
) - さらに、標準出力の出力先を、
/dev/null
に設定する(>/dev/null
)
正しい表記
command >/dev/null 2>&1
正しい記法の場合についても、処理の流れを見直してみると、以下のようになります。
- 標準出力の出力先を、
/dev/null
に設定する。 - 標準エラー出力の出力先を、標準出力に設定されているパス(ここでは
/dev/null
)に設定する(2>&1
)
おわりに
と、ここまで書いたうえで、いい加減、>/dev/null 2>&1と書くのをやめたらどうか (追記あり)内の、下記記載を読んで再度混乱しています。
a.txt 2>&1 と 1> a.txt 2> a.txt は意味が違う
2>&1
は「2
の出力先として&1
(1の出力先と同じもの)を設定する」という理解では、上記の2つに差分ができる理由が説明できません。すんなり説明がいったような気がしていましたが、もしかしたら重大な勘違い
をしている可能性が出てきました。
今後理解が進んだ場合に、追って訂正します。