はじめに
初心者の頃によく混乱した Bash の「標準エラー出力を標準出力に流す」記法 2>&1
についてです。
当時は意味もわからず間違って 2&>1
とかやってましたが、今改めてこの 2&>1
について挙動を確認してみます。
そもそも 2>&1
とは
- 標準エラー出力
2
を 標準出力1
と同じ設定にする (と覚えてます)- 結果、2つとも同じところ (標準出力) に出力される
叩いてみる
手っ取り早く標準エラー出力を出せる以下コマンド (?) を使います。
$ aaa
-bash: aaa: command not found
正しい方法 2>&1
# 標準出力をファイルに保存
$ aaa > /tmp/stdout_check.log 2>&1
$ cat /tmp/stdout_check.log
-bash: aaa: command not found
確かに標準エラー出力が標準出力と一緒にファイルへリダイレクトされています。
間違った方法 2&>1
$ aaa > /tmp/stdout_check.log 2&>1
$ cat /tmp/stdout_check.log
$
ファイルは空っぽ。
試しにファイルへのリダイレクトをなくしてみます。
$ aaa 2&>1
$
当然ながら何も出力されません。
ここでカレントディレクトリを見てみると
$ ls -l 1
-rw-r--r-- 1 togawa togawa 30 11月 24 13:57 1
$ cat 1
-bash: aaa: command not found
1
というファイルができています。どうやら 1
というファイルにリダイレクトされてしまったようです。
もう少し紐解いてみる
引数をとるコマンド grep で試す
$ echo test | grep test 2&>1
$ cat 1
grep: 2: No such file or directory
grep を使い test という文字列を検索してみます。
2: No such file or directory
というエラーメッセージを得ました。
想定では標準入力が検索対象となるはずでしたが、実際は 2
というファイルを読み込もうとしていたようです。
ここで、上記コマンドをスペースで整形すると以下のようになります。
$ grep test 2 &>1
紐解くと
-
grep test 2
: test という文字列を 2 というファイルから検索 -
&>1
: 標準エラー出力と標準出力を 1 というファイルにリダイレクト-
>1 2>&1
したのと同じ
-
となります。
つまり、2&>1
は「2 という引数」と「&>1 というリダイレクト」に分解されることになります。
aaa 2&>1
のときも、実は aaa
に 2
という引数を与えていたのでした。
まとめ
- 標準エラー出力を標準出力に流すための正しい書き方は
2>&1
- 間違った書き方
2&>1
は「2 という引数」と「&>1 というリダイレクト」に分解される- 標準エラー/標準出力いずれも "1" というファイルに書き込まれてしまう
- これに限らず、何事も丸暗記ではなくて根本から理解して使うと安全