標準入出力とは - stdin / stdout / stderr の仕組み

標準入出力とは - stdin / stdout / stderr の仕組み

この記事でできるようになること

  • 標準入力・標準出力・標準エラー出力の役割を区別できる
  • コマンドの入出力がどこへ流れるかをイメージできる

前提知識(先に読むと理解しやすい記事)

標準入出力って何だろう?

コマンドを学んでいくと、> file|(パイプ)という記号によく出会う。この記号の裏側にあるのが「標準入出力ひょうじゅんにゅうしゅつりょく(stdin / stdout / stderr)」という仕組みだ。

この記事では、3つの標準入出力の役割、出力が2種類に分かれる理由、リダイレクトとパイプの使い方を、リナとライニー先輩の会話で整理する。

この記事でわかること

  • stdin / stdout / stderr の3つがそれぞれ何を担当しているか
  • なぜ出力が stdout と stderr の2種類に分かれているのか
  • 番号 0 / 1 / 2(ファイルディスクリプタ)の意味
  • > 2> &> で出力先を切り替える方法
  • パイプ | と入力リダイレクト < の使い方

1. 標準入出力とは何か?

結論: 標準入出力は、コマンドが持つ3つの通り道。データを受け取る口が1つ、結果を出す口とエラーを出す口が2つある。それぞれ stdin・stdout・stderr と呼ぶ。

リナ: ライニー先輩、「標準入出力」という言葉を見ました。難しそうです…
ライニー先輩: 名前は難しそうだけど、考え方は簡単だよ。工場をイメージして。材料を運び込む入り口、完成品を送り出す出口、不良品を知らせるアラームの出口——コマンドにもこの3つがあるんだ。
リナ: 工場みたいに、入り口と出口が3つあるんですね。
ライニー先輩: そう。名前も工場の仕組みと同じで、役割ごとに決まっている。
  • 標準入力(stdin。データの入り口): 材料が運び込まれる入り口にあたる
  • 標準出力(stdout。結果を出す出口): 完成品が流れる出口にあたる
  • 標準エラー出力(stderr。エラー専用の出口): 不良品を知らせるアラームにあたる

コマンドを表す箱に stdin (0) から入り、stdout (1) と stderr (2) の2つの出口へ分かれていく流れ図

図1: 入り口は stdin の1つ、出口は stdout と stderr の2つ。かっこ内の数字は「番号 0 / 1 / 2 って何?」で説明する。

リナ: 入り口が1つ、出口が2つ、ですね。
ライニー先輩: その通り。普段は意識しなくても、コマンドは必ずこの3つの通り道を持って動いている。

「標準」の意味

「標準」とは「特に指定しなければ使う、決まった通り道」という意味。例えば ls の結果が画面に出るのは、stdout の標準の行き先が画面(ターミナル入力したコマンドを解釈してコンピュータに実行させる対話プログラム。)だからだ。この行き先を後から変える操作が、リダイレクトとパイプの正体だ。

2. なぜ出力が stdout と stderr に分かれているの?

結論: 「次に渡したい結果」と「人に読ませたいエラー」を混ぜないためだ。分けておけば、結果だけを保存したり、エラーだけを取り出したりできる。

リナ: でも、なんで出口が2つもあるんですか? 一つにまとめたほうが楽じゃないですか?
ライニー先輩: いい質問だね。たくさんのファイルを処理して、結果をファイルに保存する場面を考えよう。もし処理結果とエラーメッセージが同じ出口から出てきたら、保存したファイルにエラー文が混ざってしまう。
リナ: あ、たしかに。きれいな結果だけが欲しいのに、ゴミが混ざりますね。
ライニー先輩: そう。だから Linux は最初から出口を分けている。
  • stdout = 正常な結果(次の処理やファイルに渡したいデータ)
  • stderr = エラーや警告(人に知らせたいメッセージ)
ライニー先輩: こうしておけば、結果だけをファイルに保存しても、エラーは画面に出る。だから見落とさずに済むんだ。
リナ: なるほど! 役割で出口を分けているんですね。工場の入り口と出口の話と同じです。

さっきの工場の例で言うと

stdout は完成品を運ぶベルトコンベア、stderr は不良品を知らせるアラーム。完成品の箱(ファイル)にアラームの音を入れたくないから、出口を分けてある。

3. 番号 0 / 1 / 2 って何?

結論: stdin・stdout・stderr には 0・1・2 という番号(ファイルディスクリプタ)が割り当てられている。2>2 はこの番号を指す。

リナ: 設定例で 2> という書き方を見ました。この 2 は何ですか?
ライニー先輩: それは stderr の番号だ。3つの標準入出力には、それぞれ整数の背番号せばんごうがついている。
リナ: 背番号、ですか…?
ライニー先輩: 「ファイルディスクリプタ(FD と略されることもある)」という、コマンドが入出力の口を区別するための番号だよ。覚えるのは3つだけ。
番号 名前 役割
0 stdin 標準入力(入り口)
1 stdout 標準出力(通常の出口)
2 stderr 標準エラー出力(出口)

番号と記号の対応

リダイレクトの記号は、この番号と直結している。

  • >1> の省略形(stdout を送る)
  • 2> は stderr を送る
  • <0< の省略形(stdin から読む)

2> の 2 は stderr の背番号」と覚えれば、記号の意味がわかる。

4. リダイレクトで出力先を変えるには?

結論: > で stdout を、2> で stderr をファイルへ送れる。両方まとめるなら > file 2>&1 または &> file

リナ: 出口を分けているのはわかりました。結果だけをファイルに保存するには、どうすればいいですか?
ライニー先輩: 「リダイレクト」を使うよ。出口の行き先を、画面からファイルに付け替える操作だ。まずは stdout をファイルに保存してみよう。
ls /etc > filelist.txt

> を使うと、画面に出るはずだった stdout の内容が filelist.txt に書き込まれる。画面には何も表示されない。> は上書き、>> は追記になる。

リナ: > は便利ですね。さっそく使ってみます。ls /etc > notes.txt を実行して、そのあとに ls /home > notes.txt も実行しました。
ライニー先輩: ちょっと待って。その2回目のコマンドで、1回目に保存した notes.txt の中身は消えてしまったよ。
リナ: え! 上書きされたんですか…! 前の結果を見返したかったのに…
ライニー先輩: > は上書き専用なんだ。同じファイル名にもう一度 > を使うと、前の中身は消えてしまう。残しておきたいときは >>(追記)を使おう。
リナ: > は「保存」じゃなくて「置き換え」なんですね...! 次からは >> を使います。

> による上書き事故に注意

GUI でファイルを保存するときは「同じ名前のファイルがあります。上書きしますか?」という確認が出ます。> には、この確認がありません。Enter を押した瞬間に、元の中身は消えます。ゴミ箱にも残りません。

安全に使うために、次の2つを習慣にしましょう。

  • 前の内容を残したいときは >>(追記)を使う
  • 保存する前に ls ファイル名 で、同じ名前のファイルがないか確かめる

なお、本サイトの仮想かそうターミナルは学習用です。ここで > を試しても、あなたのパソコンのファイルは壊れません。安心して練習してください。

エラーだけを保存したいときは 2> を使う。

ls /not-exist 2> errors.txt

このとき画面には何も表示されない。errors.txt の中に、次の1行が記録される。

ls: cannot access '/not-exist': No such file or directory
リナ: stdout は >、stderr は 2> ですね。両方を1つのファイルにまとめたいときは、どうすればいいですか?
ライニー先輩: そのときは 2>&1 を付け足す。「stderr(2)を、stdout(1)と同じ行き先に流す」という意味だよ。
command > output.txt 2>&1

2>&1 は順番が大事

2>&1 は「stderr を、その時点の stdout の行き先に合わせる」という意味だ。そのため > output.txt先に書く。順番を逆にして command 2>&1 > output.txt と書くと、stderr は古い行き先(画面)のままになる。順番を気にしたくないなら、&> file という書き方でも両方まとめて送れる。ただし、これは bash(Ubuntu などで標準的に使われるシェル。打ったコマンドを受け取って実行するプログラム)専用の書き方だ。

command &> output.txt

5. パイプと標準入力はどう使う?

結論: パイプ | は左コマンドの stdout を右コマンドの stdin につなぐ。< はファイルの中身を stdin として渡す。

リナ: stdin(入り口)は、いつ使うんですか? あまり意識したことがなくて…
ライニー先輩: 実は、パイプを使うたびに stdin が働いているんだ。パイプ | は、左のコマンドの stdout を、右のコマンドの stdin に直接つなぐ仕組みだよ。
ls /etc | grep conf

この例では、ls /etc の出力(stdout)が、そのまま grep conf の入力(stdin)に流れ込む。grep は入力の中から conf を含む行だけを拾い出す。

流れのイメージ

ls /etc  ──stdout──▶  |  ──stdin──▶  grep conf  ──stdout──▶  画面

パイプは、前のコマンドの出口と、次のコマンドの入り口を直結するホースのようなものだ。

ファイルの中身を stdin として渡したいときは < を使う。

sort < names.txt

これは names.txt の中身を sort の標準入力に流し込み、並べ替えて表示する。結果は sort names.txt と同じだ。でも、「ファイルを stdin につなぐ」という標準入力の動きが分かりやすい例になっている。

パイプやリダイレクトをもっと実践的に練習したいなら、パイプとリダイレクトの基本 で手を動かしながら学べる。出力を画面とファイルの両方に出したいときは tee コマンドの使い方 も便利だ。

ミニ課題

結論: stdout・stderr のリダイレクトとパイプを、実際に手を動かして確認する。

ライニー先輩: それじゃ、3つ課題を出すよ。コマンド名がすぐに浮かばなくても、ヒントを順番に開けば大丈夫。
リナ: やってみます!

課題1: ls /etc の結果だけを etc-list.txt に保存しよう(画面には何も表示しない)

ヒント1(方向づけ)を見る

出力の行き先を、画面からファイルに変える記号がある。上書きでよい。

ヒント2(コマンド名)を見る

> を使う。

答えを見る
ls /etc > etc-list.txt

画面には何も出ず、etc-list.txt/etc の一覧が保存される。

課題2: 存在しないディレクトリファイルをまとめて整理する入れ物。Windows や macOS の「フォルダ」と同じもの。ls で指定し、そのエラーメッセージだけを err.txt に保存しよう(画面にはエラーを出さない)

ヒント1(方向づけ)を見る

出力ではなく、エラー専用の出口だけをファイルに向ける記号がある。

ヒント2(コマンド名)を見る

2> を使う。

答えを見る
ls /no-such-dir 2> err.txt

画面には何も出ず、err.txtls: cannot access '/no-such-dir': No such file or directory が記録される。

課題3: ls /etc の結果から、conf を含む行だけを画面に表示しよう(ファイルには保存しない)

ヒント1(方向づけ)を見る

前のコマンドの出力を、そのまま次のコマンドの入力として渡すしくみを使う。

ヒント2(コマンド名)を見る

パイプ |grep を使う。

答えを見る
ls /etc | grep conf

ls /etc の出力から conf を含む行だけが画面に表示される。

まとめ

  • 標準入出力は stdin(入力)/ stdout(通常の出力)/ stderr(エラー出力)の3つの通り道
  • 出力が2種類あるのは「結果」と「エラー」を混ぜないため
  • 3つには番号 0 / 1 / 2(ファイルディスクリプタ)が割り当てられている
  • > で stdout、2> で stderr をファイルへ送れる(両方なら > file 2>&1 または &> file
  • パイプ | は stdout を次の stdin につなぎ、< はファイルを stdin として渡す

次に読む

この記事を共有

次の一手