sh のリダイレクト

一度理解してもすぐに忘れて混乱するのでメモ。

$ command 2>&1 >hoge

このコマンドラインを実行すると command の標準出力(1)は hoge へ書かれ、command の標準エラー出力(2)は画面に出力される。



間違った理解をしている時は、頭の中では配管工事*1をイメージしている。

通常の配管は次のようになっている。

0──→0
1──→1
2──→2

以下のコマンドラインを実行すると、

$ command 2>&1 >hoge

2>&1 の部分で 2 から 1 へ配管工事が行われ

0──→0
1─┬→1
2─┘  2

となり、次に >hoge の部分で

0──→0
1─┬→hoge
2─┘  2

となるという誤った理解をしてしまう。



正しい理解は、駅のホームの番号と、電車の行き先というイメージ。

通常は、ホームの番号とそのホームに入ってくる電車の行き先は次のようになっている。

(ホームの番号:「電車の行き先」)
0:「キーボード」
1:「画面」
2:「画面」

以下のコマンドラインを実行すると、

$ command 2>&1 >hoge

2>&1 の部分で 2 番線の電車の行き先は、1 番線の電車の行き先と同じになる。

0:「キーボード」
1:「画面」
2:「画面」 ← 1 番線の電車の行き先と同じなる*2

次に >hoge の部分で 1 番線の電車の行き先を hoge に変更する*3

0:「キーボード」
1:「hoge」 ← 行き先が変更される
2:「画面」

したがって、command の標準出力(1)は hoge へ書かれ、command の標準エラー出力(2)は画面に出力される。



上記のコマンドラインと似て非なる次のコマンドラインの場合、

$ command >hoge 2>&1

>hoge の部分で 1 番線の電車の行き先を hoge に変更する。

0:「キーボード」
1:「hoge」 ← 行き先が変更される
2:「画面」

2>&1 の部分で 2 番線の電車の行き先は、1 番線の電車の行き先と同じになる。

0:「キーボード」
1:「hoge」
2:「hoge」 ← 1 番線の電車の行き先と同じなる

したがって、command の標準出力(1)と標準エラー出力(2)はどちらも hoge へ書かれることになる。



ちゃんと調べてないが

  • a>&b は dup2(b, a);
  • c>filename は fd = open("filename"); dup2(fd, c);

*1:「|」の名前がパイプであることに影響されているかもしれない

*2:もともと同じなので変化しない

*3:>hoge は 1>hoge と同じ意味である