はじめに
以下のようなbashでのリダイレクト操作に関して、個人的に最もしっくりきた説明を記載します。
cmd > test.log
cmd 2> test.log
cmd > test.log 2>&1
cmd > /dev/null 2>&1
cmd 2>&1 > test.log
cmd1 2>&1 | cmd2
cmd1 2>&1 1>/dev/null | cmd2
cmd 3>&2 2>&1 1>&3
以下に記載する内容は**「こう考えると上記各式の違いを理解できる」**、という内容になります。
より詳しい仕様については多くの他サイトで説明されていますので、そちらをご覧ください。
目次
1.リダイレクトの3つのルール
2.イメージ図
3.各リダイレクト操作の意味を解説
3.1.cmd > test.log
3.2.cmd 2> test.log
3.3.cmd > test.log 2>&1
3.4.cmd > /dev/null 2>&1
3.5.cmd 2>&1 > test.log
3.6.cmd1 2>&1 | cmd2
3.7.cmd1 2>&1 1>/dev/null | cmd2
3.8.cmd 3>&2 2>&1 1>&3
まとめ
1.リダイレクトの3つのルール
冒頭で述べた各式の違いを理解するのに覚える必要があるルールは以下3つです。
ルール1 A>hoge (Aの向き先をhogeにする)
ルール2 A>&B (Aの向き先をBが現在指し示す先にする(Bと同じ向き先を向くようにする))
ルール3 リダイレクト記述が複数ある場合左から処理される
※A, Bは数字。Aを省略した場合、A=1とみなされる。
2.イメージ図
※そもそも標準出力、標準エラー出力って何?と思った方は、以下をご覧ください。詳しく解説されています。
標準入力・標準出力ってなに?
それでは、このイメージ図と3つのルールでリダイレクト操作を考えます。
3.各リダイレクト操作の意味を解説
では3つのルールとイメージ図を使って、冒頭の各式をひもといていきます。
3.1.cmd > test.log
ルール1 A>hoge、Aの向き先をhogeにする。ただしAを省略した場合は1とみなされる。
従って、cmd 1> test.logと同じになり、以下のようになります。
3.2.cmd 2> test.log
ルール1 A>hoge、Aの向き先をhogeにする。
以下のように2の向き先をtest.logにします。
3.3.cmd > test.log 2>&1
ルール3、リダイレクト記述が複数ある場合左から処理される、ため、まずはcmd > test.logを見ます。
これは、ルール1 A>hoge、Aの向き先をhogeにする(ただしA省略時は1とみなす)、ので以下のようになります。
続いて 2>&1。
ルール2 A>&B、Aの向き先をBが現在指し示す先にする。
1が現在指し示す先はtest.logです。そのため2の向き先をtest.logにする(以下)。
結果として、1(標準出力の内容)も2(標準エラー出力の内容)もtest.logに出力される。
3.4.cmd > /dev/null 2>&1
/dev/nullにリダイレクトされたものは全て棄てられます。どこにも出力されません。
式の形としては3.3.cmd > test.log 2>&1と同じですので、
結果として1(標準出力の内容)も2(標準エラー出力の内容)も棄てられます。
3.5.cmd 2>&1 > test.log
これは3.3.cmd > test.log 2>&1を逆の順番で書いた場合。
ルール3に従い左から順に処理します。
ルール2 A>&B、Aの向き先をBが現在指し示す先にする、ので2の向き先を1が現在指し示す先にします(以下)。
続いて、 > test.logを処理します。
ルール1 A>hoge、Aの向き先をhogeにする(ただしA省略時は1とみなす)、ので1>test.logは以下のようになります。
結果として、1(標準出力の内容)はtest.logに出力され、2(エラー出力の内容)は標準出力(画面)に出力されます。
このように式の順序を変えると全く異なる結果になります。
3.6.cmd1 2>&1 | cmd2
パイプ(|)は、標準出力のみを渡します。そのため標準エラー出力もパイプで渡したい場合このようにします。
ルール2 A>&B、Aの向き先をBが現在指し示す先にする、ので2の向き先を1が現在指し示す先にします(以下)。
これで1の内容2の内容両方が標準出力へ出力され、パイプでcmd2へ渡されます。
3.7.cmd1 2>&1 1>/dev/null | cmd2
標準エラー出力だけをパイプで渡したい場合このようにします。
ルール2 A>&B、Aの向き先をBが現在指し示す先にする、ので2の向き先を1が現在指し示す先にします(以下)。
続いて1>/dev/nullは、
ルール1 A>hoge、Aの向き先をhogeにする、ので以下になります。
結果として、1の内容は棄てられ、2(エラー出力)のみが標準出力に出力され、パイプでcmd2へ渡されます。
3.8.cmd 3>&2 2>&1 1>&3
これは標準出力と標準エラー出力の内容を入れ替えます。
ルール2 A>&B、Aの向き先をBが現在指し示す先にする、およびルール3に従い左から順に処理します(以下)。
結果として、2の内容が標準出力へ、1の内容が標準エラー出力へ出力されます。
まとめ
本記事では「冒頭で記載したリダイレクトを含む式」の違いを理解するための考え方を記載しました。
なおリダイレクトのその他の詳細な説明に関しては、他にたくさん説明されているサイトがあるのでそちらをご参照ください。