Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

初心者の頃によく混乱した 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 は「2 という引数」と「&>1 というリダイレクト」に分解される
    • 標準エラー/標準出力いずれも "1" というファイルに書き込まれてしまう
  • これに限らず、何事も丸暗記ではなくて根本から理解して使うと安全

参考

tsubasaogawa
温故知新
openwork
転職・就職のための情報プラットフォーム「OpenWork」の企画・開発・運用をしています。
https://vorkers.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away