Linux: 標準ストリームとリダイレクト — stdin / stdout / stderr

Linuxはすべてのプログラムを「フィルター」として扱います — どこかから入力を受け取り、処理し、結果を出力します。入力と出力の経路が標準ストリームです。

📋 前提条件:まず以下を完了していること

1. このレッスンで学ぶこと


2. エラーで画面が埋め尽くされるストーリー

(1) 悩み:出力が混在して必要な情報が見つけにくい

小明はapt updateを実行し、成功メッセージと赤いエラーメッセージが画面に混在してスクロールしました。成功した結果だけを保存し、エラーは別に確認したいと思いました。

(2) リダイレクトで出力を分割

ボブがリダイレクトを教えてくれました:

BASH
# Save success messages to success.log, errors to error.log
sudo apt update > success.log 2> error.log

# View the errors
cat error.log

(3) 得られるもの:精密な出力制御

小明は異なる出力を別々のストリームに振り分ける方法を学びました — ログファイルには成功のみ、ターミナルには重要な情報のみ、エラーは別途保存してトラブルシューティングに活用。


3. 知識ポイント

(1) 3つの標準ストリーム

Linuxプログラムが起動すると、自動的に3つのファイル記述子を受け取ります:

ファイル記述子 名前 デフォルト接続先 用途
0 stdin キーボード プログラムの入力
1 stdout ターミナル画面 プログラムの通常出力
2 stderr ターミナル画面 プログラムのエラー出力
TEXT

          ┌──────────┐
stdin ──→│          │──→ stdout
(keyboard)│  Program │    (screen)
          │          │──→ stderr
          └──────────┘    (screen)

(2) リダイレクト演算子

演算子 意味
> stdoutをファイルに書き込み(上書き) ls > files.txt
>> stdoutをファイルに追記 echo "done" >> log.txt
< ファイルからstdinを読み取り sort < list.txt
2> stderrをファイルに書き込み cmd 2> error.log
2>> stderrをファイルに追記 cmd 2>> error.log
&> stdoutとstderrの両方をファイルに書き込み cmd &> all.log
&>> stdoutとstderrの両方をファイルに追記 cmd &>> all.log
2>&1 stderrをstdoutにマージ cmd > log.txt 2>&1

ℹ️ 注意>は上書き(既存ファイルの内容は消去)、>>は追記(ファイル末尾に追加)。履歴ログを残す場合は>>、クリーンな状態が必要な場合は>を使います。>の誤用は重要なログファイルを上書きする可能性があります。

(3) /dev/null — ブラックホール

/dev/nullは特殊なデバイスファイル — 書き込まれたデータはすべて破棄され、読み出しは何も返しません。

💡 ヒント/dev/nullはLinuxの「ブラックホールデバイス」 — カーネルがドライバレベルで書き込まれたデータを直接破棄し、ディスク容量を使わず、満になることもありません。よく使われるのはコマンド出力の抑制:command &> /dev/nullで全出力を完全抑制、command 2> /dev/nullでエラーのみ抑制。

TEXT
# Discard all output
command > /dev/null 2>&1

# Or the shorter form
command &> /dev/null

# Only discard errors
command 2> /dev/null

# Only discard normal output
command > /dev/null

(4) ▶ サンプル:コマンド出力をファイルに保存

BASH
# Overwrite write
ls ~ > home-directory.txt
cat home-directory.txt

# Append write
echo "A new line" >> home-directory.txt
echo "Another line" >> home-directory.txt
cat home-directory.txt

出力:

TEXT
Desktop
Documents
    Downloads
A new line
Another line

(5) ▶ サンプル:通常出力とエラー出力の分離

BASH
# Save success messages, view errors separately
find /etc -name "*.conf" > found.txt 2> errors.txt

# View results
echo "=== Found config files ==="
head -5 found.txt

echo "=== Error messages ==="
cat errors.txt

出力:

TEXT
=== Found config files ===
/etc/adduser.conf
/etc/ca-certificates.conf
/etc/debconf.conf
/etc/deluser.conf
/etc/fuse.conf
=== Error messages ===
find: '/etc/ssl/private': Permission denied

(6) ▶ サンプル:出力のマージ

BASH
# Method 1: &> (bash 4+)
grep -r "error" /var/log/ &> all-results.txt

# Method 2: 2>&1 (more portable)
grep -r "error" /var/log/ > all-results.txt 2>&1

# Both methods produce the same result — stdout and stderr go to the same file

> 💡 ヒント:`2>&1`の順序は重要です!`cmd > log.txt 2>&1`が正解 — まずstdoutをファイルにリダイレクトし、次にstderrをstdout(今はファイルを指している)にマージします。`cmd 2>&1 > log.txt`と書くと、stderrがまず画面のstdoutにマージされ、その後stdoutがファイルにリダイレクトされるため、stderrは画面に残ります。

出力:

TEXT
$ wc -l all-results.txt
42 all-results.txt

(7) ▶ サンプル:/dev/nullで出力を抑制

BASH
# Completely silent execution
sudo apt update > /dev/null 2>&1

# Shorter form
sudo apt update &> /dev/null

# Only suppress errors
find / -name "*.py" 2> /dev/null

出力:

TEXT
(No output — all errors and normal results suppressed)

(8) ▶ サンプル:heredoc — スクリプトに複数行テキストを埋め込む

BASH
# Create a multi-line configuration file
cat << EOF > nginx.conf
server {
    listen 80;
    server_name example.com;
    root /var/www/html;
}
EOF

# Append multi-line text
cat << EOF >> ~/.bashrc
# Add PATH
export PATH="\$PATH:\$HOME/scripts"
EOF

# Variables in heredoc won't be expanded (use quoted 'EOF')
cat << 'EOF' > greeting.sh
#!/bin/bash
echo "Hello, $USER"    # $USER remains as variable name
EOF

出力:

TEXT
server {
    listen 80;
    server_name example.com;
    root /var/www/html;
}

(9) ▶ 総合例:プログラムコンパイル時の出力管理

BASH
# Compile a C program, logging output and errors separately
gcc main.c -o app \
    > build.log \        # Compilation success messages
    2> build-errors.log  # Compilation error messages

# If compilation succeeds, build-errors.log is empty
# If compilation fails, view the errors
if [ -s build-errors.log ]; then
    echo "❌ Compilation failed, errors:"
    cat build-errors.log
else
    echo "✅ Compilation successful!"
fi

❓ よくある質問

Q: >|(パイプ)の違いは? A: \1

Q: 2>&1の意味は? A: \1

Q: 2>&1の代わりに&>を使う理由は? A: &>はbash 4+の短縮形でより簡潔です。2>&1はより移植性が高い(shでも動作)。両者は同じ動作をします。

Q: /dev/nullは真空ですか?満になることは? A: いいえ。/dev/nullに書き込まれたデータはカーネルによって直接破棄され、ディスク容量を一切使用しません。実質的に「無限容量のブラックホール」です。

Q: heredocのEOFは大文字でなければなりませんか? A: いいえ。EOFは慣習に過ぎません。任意の文字列(EOLEND__EOF__)が使えます。重要なのは開始と終了のマーカーが正確に一致することです。


📖 まとめ


📝 練習問題

  1. 基本(難易度 ⭐)ls -laの出力をhome-list.txtに保存し、>>で現在の日付を追記する
  2. 中級(難易度 ⭐⭐)find / -name "*.py" 2> errors.txtを実行して権限拒否エラーを確認し、&>でstdoutとstderrを1ファイルに取得し、/dev/nullでエラー出力を抑制する
  3. 上級(難易度 ⭐⭐⭐):heredocで5行の設定ファイルを作成し、4つのリダイレクト方法(>2>&>>>)をデモするスクリプトを作成し、それぞれの適用場面を説明する
Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%