Linux: 標準ストリームとリダイレクト — stdin / stdout / stderr
Linuxはすべてのプログラムを「フィルター」として扱います — どこかから入力を受け取り、処理し、結果を出力します。入力と出力の経路が標準ストリームです。
📋 前提条件:まず以下を完了していること
- レッスン5:ファイルとディレクトリの操作
1. このレッスンで学ぶこと
- 標準入力、出力、エラーの概念
>と>>の違い2>によるエラーリダイレクト&>による両ストリームのリダイレクト/dev/nullの応用
2. エラーで画面が埋め尽くされるストーリー
(1) 悩み:出力が混在して必要な情報が見つけにくい
小明はapt updateを実行し、成功メッセージと赤いエラーメッセージが画面に混在してスクロールしました。成功した結果だけを保存し、エラーは別に確認したいと思いました。
(2) リダイレクトで出力を分割
ボブがリダイレクトを教えてくれました:
# 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 | ターミナル画面 | プログラムのエラー出力 |
┌──────────┐
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でエラーのみ抑制。
# 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) ▶ サンプル:コマンド出力をファイルに保存
# 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
出力:
TEXTDesktop Documents Downloads A new line Another line
(5) ▶ サンプル:通常出力とエラー出力の分離
# 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) ▶ サンプル:出力のマージ
# 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で出力を抑制
# 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 — スクリプトに複数行テキストを埋め込む
# 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
出力:
TEXTserver { listen 80; server_name example.com; root /var/www/html; }
(9) ▶ 総合例:プログラムコンパイル時の出力管理
# 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は慣習に過ぎません。任意の文字列(EOL、END、__EOF__)が使えます。重要なのは開始と終了のマーカーが正確に一致することです。
📖 まとめ
- 標準入力(stdin/0)→ プログラム → 標準出力(stdout/1)+ 標準エラー(stderr/2)
>は上書き、>>は追記、2>はエラーリダイレクト&>は出力マージ、/dev/nullは出力破棄2>&1はstderrをstdoutにマージ(順序に注意)- heredoc
<< EOF ... EOFでスクリプトに複数行テキストを埋め込み
📝 練習問題
- 基本(難易度 ⭐):
ls -laの出力をhome-list.txtに保存し、>>で現在の日付を追記する - 中級(難易度 ⭐⭐):
find / -name "*.py" 2> errors.txtを実行して権限拒否エラーを確認し、&>でstdoutとstderrを1ファイルに取得し、/dev/nullでエラー出力を抑制する - 上級(難易度 ⭐⭐⭐):heredocで5行の設定ファイルを作成し、4つのリダイレクト方法(
>、2>、&>、>>)をデモするスクリプトを作成し、それぞれの適用場面を説明する