ShellScript
Bash
Linux
shell

リダイレクトとして 2&>1 を使うと何が起きるのか?


はじめに

初心者の頃によく混乱した Bash の「標準エラー出力を標準出力に流す」記法 2>&1 についてです。

当時は意味もわからず間違って 2&>1 とかやってましたが、今改めてこの 2&>1 について挙動を確認してみます。


そもそも 2>&1 とは


  • 標準エラー出力 2 を 標準出力 1 と同じ設定にする (と覚えてます)


    • 結果、2つとも同じところ (標準出力) に出力される




叩いてみる

手っ取り早く標準エラー出力を出せる以下コマンド (?) を使います。

$ aaa

-bash: aaa: command not found


:thumbsup_tone1: 正しい方法 2>&1

# 標準出力をファイルに保存

$ aaa > /tmp/stdout_check.log 2>&1
$ cat /tmp/stdout_check.log
-bash: aaa: command not found

確かに標準エラー出力が標準出力と一緒にファイルへリダイレクトされています。


:thumbsdown_tone1: 間違った方法 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 のときも、実は aaa2 という引数を与えていたのでした。


まとめ



  • 2&>1 は「2 という引数」と「&>1 というリダイレクト」に分解される


  • & の位置がひとつずれるだけで変なファイルができてしまうので注意


    • しかも標準エラー/標準出力いずれも "1" というファイルに書き込まれてしまう


    • $? も異常値になるはず



  • これに限らず、何事も丸暗記ではなくて根本から理解して使うと安全


参考