Linuxの標準出力・標準エラー出力を理解する|2>&1って何をしている?

こんにちは、さるまりんです 🐒🔧

いろんな言語のプログラミングやコマンドラインで、ときどき呪文のような書き方に出逢いませんか?

たとえば、Linuxのこんなの。

command > log.txt 2>&1

最初に見たときは、

「なんだこれ……?」

ってなりやすいと思います。

でも、こういう呪文っぽいものの意味がわかると、ちょっと楽しくなってきます。

新しいスキルをひとつ手に入れて、レベルアップした気持ちになります。
魔術師レベルアップです。

今回は、僕にとって長い間使いこなせなかったLinuxでよく出てくる、

  • 標準出力
  • 標準エラー出力
  • 2>&1

について、できるだけシンプルに整理してみたいと思います。


■ Linuxの出力はひとつではない

Linuxでコマンドを実行すると、画面に結果が表示されます。

たとえば、こんなコマンドです。

ls

ファイルやディレクトリの一覧が表示されます。

一方で、存在しないファイルを指定すると、エラーメッセージが表示されます。

ls no-such-file

たとえば、こんな感じです。

ls: cannot access 'no-such-file': No such file or directory

どちらも画面に表示されるので、最初は同じものに見えます。

でもLinuxの中では、これらは別のものとして扱われています。

通常の結果は標準出力

エラーメッセージは標準エラー出力

という別の出口から出ています。


■ 標準出力とは

標準出力は、コマンドの普通の結果が出る場所です。

英語では stdout と呼ばれます。

たとえば、次のようなコマンドの結果です。

ls
echo "hello"
date

これらは、エラーではなく「コマンドが普通に出した結果」です。

C++で言うと、cout のストリームに近いものですね。


■ 標準エラー出力とは

標準エラー出力は、エラーメッセージが出る場所です。

英語では stderr と呼ばれます。

たとえば、存在しないファイルを見ようとした場合です。

ls no-such-file

このとき表示されるエラーメッセージは、標準出力ではなく、標準エラー出力に出ます。

画面に表示されるだけだと違いが見えにくいのですが、Linuxとしては別の出口から出している、ということです。

こっちはC++で言うと、cerr に近いものです。


■ 数字で見ると少しわかりやすい

Linuxでは、標準出力や標準エラー出力に番号がついています。

番号 名前 意味
0 標準入力 入力
1 標準出力 普通の結果
2 標準エラー出力 エラー

今回大事なのは、12 です。

1 が標準出力。

2 が標準エラー出力。

つまり、2>&12 は、標準エラー出力を指しています。

少し呪文がほどけてきました。


■ > は標準出力をファイルに書く

まずは、普通のリダイレクトから見てみます。

ls > out.log

これは、ls の結果を画面に出さず、out.log に書き込むという意味です。

> は標準出力をファイルへ送ります。

つまり、これは本当はこういう意味に近いです。

ls 1> out.log

1 は省略できるので、普段は書かないことが多いです。


■ エラーは > だけではファイルに入らない

では、エラーが出るコマンドを試してみます。

ls no-such-file > out.log

この場合、エラーメッセージは画面に表示されます。

out.log には入りません。

なぜかというと、> が送っているのは標準出力だけだからです。

エラーメッセージは標準エラー出力なので、別の出口から出ています。

ここが大事なところです。

画面に出ているものが、すべて標準出力とは限りません。


■ 2> は標準エラー出力をファイルに書く

標準エラー出力をファイルに書きたいときは、2> を使います。

ls no-such-file 2> error.log

これで、エラーメッセージが error.log に書き込まれます。

普通の結果をファイルに出したいときは >

エラーをファイルに出したいときは 2>

2 は、さっきの標準出力のようには省略できないので、ちゃんと書きます。

ここまでわかると、呪文の中身が見やすくなってきたんじゃないでしょうか。


■ 標準出力と標準エラー出力を分けて保存する

標準出力と標準エラー出力は、別々のファイルに保存することもできます。

command > out.log 2> error.log

これは、

  • 普通の結果は out.log
  • エラーは error.log

に書き込む、という意味です。

ログを分けて見たいときには便利です。

たとえば、正常な処理結果とエラーだけを分けて見たい場合です。


■ では 2>&1 は何をしているのか

いよいよです。全部合わせてみましょう。

command > log.txt 2>&1

この 2>&1 は、

標準エラー出力を、標準出力と同じ場所へ送る

という意味です。

もう少し分けて見ると、こうです。

command > log.txt

まず、標準出力を log.txt に送ります。

そのあとで、

2>&1

標準エラー出力も、標準出力と同じ場所へ送ります。

この場合、標準出力はすでに log.txt に向いています。

なので、標準エラー出力も log.txt に入ります。

つまり、

command > log.txt 2>&1

は、

普通の結果もエラーも、まとめて log.txt に書き出す

という意味になります。


■ 順番には少し注意が必要

ここで少しだけ注意があります。

リダイレクトは、書いた順番に処理されます。

そのため、次の2つは同じ意味ではありません。

command > log.txt 2>&1
command 2>&1 > log.txt

1つ目は、標準出力を log.txt に向けたあとで、標準エラー出力も同じ場所へ送ります。

なので、普通の結果もエラーも log.txt に入ります。

一方、2つ目は先に標準エラー出力を「その時点の標準出力」と同じ場所へ送っています。

その時点では、標準出力はまだ画面です。

そのあとで標準出力だけを log.txt に向けるので、エラーは画面に残ることがあります。

このあたりはちょっとややこしいですね。

なので、まずは、

command > log.txt 2>&1

をひとつの形として覚えておくのが良いかもしれません。
呪文のまま?


■ 最近は &> という書き方もある

bashでは、標準出力と標準エラー出力をまとめてファイルに送る書き方として、次のようなものもあります。

command &> log.txt

これは、標準出力と標準エラー出力をまとめて log.txt に書き込む書き方です。

ただし、&> はbashで使える書き方なので、すべてのshellで同じように使えるとは限りません。

その意味でも、2>&1 の意味を知っておくと、ログやシェルスクリプトを読んだときに理解しやすいと思います。

なので、まずはこっちを覚えましょう。

command > log.txt 2>&1

この意味を分解して見るのが理解につながると思います。


■ どんなときに使うのか

2>&1 は、ログをまとめて残したいときによく使います。

たとえば、こんな場面です。

./batch.sh > batch.log 2>&1

バッチ処理の結果もエラーも、まとめて batch.log に残す形です。

cronで実行するスクリプトでも見かけることがあります。

0 3 * * * /path/to/script.sh > /path/to/script.log 2>&1

夜中に動く処理などでは、画面を見ている人がいません。

なので、あとから読めるようにログへ残しておくことが大事です。


■ まとめるか、分けるか

標準出力と標準エラー出力は、まとめることも分けることもできます。

まとめて見たいなら、こう。

command > log.txt 2>&1

分けて見たいなら、こう。

command > out.log 2> error.log

どちらが正解ということではなくて、どう使いたいかで考えるものだと思います。

小さな確認なら、まとめて1つのログでも十分です。

でも、エラーだけを追いたい場合は、分けた方が見やすいこともありますね。


■ さいごに

2>&1 は、最初に見るとかなり呪文っぽいです。

でも分解してみると、

  • 1 は標準出力
  • 2 は標準エラー出力
  • > は出力先を変える
  • 2>&1 は標準エラー出力を標準出力と同じ場所へ送る

という意味になります。

プログラミングやLinuxには、こういう呪文のような書き方がいろいろあります。

でも、ひとつ意味がわかると、少し見える世界が広がります。

「なんとなくコピペしていたもの」が、自分で読めるものに変わると嬉しくないですか?

こんなちょっとした理解の積み重ねが、モノを作ることの楽しみだなって思っています。

読んでくださってありがとうございました。

それではまた!