Linux: 環境変数とPATH — 開発環境の設定
環境変数はオペレーティングシステムが設定を保存するキーと値のペアです。シェルがコマンドを探す場所(PATH)、使用する言語(LANG)、使用するエディタ(EDITOR)などを決定します。
📋 前提条件:まず以下を完了していること
- レッスン9:ユーザーとグループの管理
1. このレッスンで学ぶこと
- 環境変数の役割
- PATHの仕組み
- exportとunsetの操作
- シェル設定ファイルの読み込み順序
- 新しいツールのPATHへの追加
2. 「command not found」ストーリー
(1) 悩み:インストールしたのに見つからない
小明はpip install --userでPythonツールhttpieをインストールしましたが、httpと入力すると:
http example.com
# Command 'http' not found
小明は混乱しました:「インストールしたのに、なぜシステムが見つけられないの?」
(2) PATH — シェルにプログラムの在り処を教える
ボブが説明しました。「プログラムはインストールされているけど、シェルはどこを探せばいいか知らない。PATH環境変数がシェルの『宝の地図』なんだ。」
echo $PATH
# /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# ~/.local/bin is not in PATH, so the Shell can't find http
ls ~/.local/bin/http*
# /home/charlie/.local/bin/http
# Add ~/.local/bin to PATH
export PATH="$PATH:$HOME/.local/bin"
http example.com # Now it works
(3) 得られるもの:仕組みを理解すればすべて解決
小明は.bashrcにexport PATH="$PATH:~/bin"を書けば永続化できることを学びました。今後新しいツールをインストールする際、インストール先ディレクトリがPATHにあるか確認すればいいと分かりました。
3. 知識ポイント
(1) 環境変数とは
環境変数はオペレーティングシステムに保存されるキーと値のペアで、すべての子プロセスに継承されます。
# View all environment variables
printenv
# View individual variables
echo $HOME
echo $USER
echo $SHELL
echo $LANG
echo $PWD
よく使う環境変数:
| 変数 | 意味 | 典型的な値 |
|---|---|---|
HOME |
現在のユーザーのホームディレクトリ | /home/alice |
USER |
現在のユーザー名 | alice |
SHELL |
現在のシェルパス | /bin/bash |
PATH |
コマンド検索パス | /usr/bin:/bin:/usr/local/bin |
LANG |
言語とエンコーディング | en_US.UTF-8 |
PWD |
現在の作業ディレクトリ | /home/alice/projects |
OLDPWD |
前の作業ディレクトリ | /etc |
EDITOR |
デフォルトエディタ | vim |
(2) PATH — コマンド検索パス
lsと入力すると、シェルはPATHにリストされた各ディレクトリを順番に検索し、lsプログラムを探します。見つかれば実行、見つからなければcommand not foundと報告します。
# View current PATH
echo $PATH
# /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# Find which directory a command is in
which ls
# /usr/bin/ls
# View all possible locations for a command (including aliases and functions)
type ls
# ls is aliased to `ls --color=auto'
(3) 環境変数の設定と削除
# Temporary setting (only effective in current Shell)
MY_VAR="hello"
# Export as environment variable (child processes can access it)
export MY_VAR="hello"
# Set and export in one command
export MY_VAR="hello"
# Unset an environment variable
unset MY_VAR
# Temporarily set for a single command (without polluting current environment)
LANG=ja_JP.UTF-8 date
(4) シェル設定ファイルの読み込み順序
読み込み順序を理解することは重要 — ~/.bashrcの変更が反映されない理由が分かります:
Login Shell (SSH login, tty login):
/etc/profile
~/.bash_profile (if it exists, the following two are skipped)
~/.bash_login
~/.profile
Non-login Shell (opening a new terminal):
/etc/bash.bashrc
~/.bashrc
ℹ️ 注意:
.bashrcと.profileは異なるタイミングで読み込まれます — SSHログインは.profileを、新しいターミナルの起動は.bashrcを読み込みます。ベストプラクティスは.profileにsource ~/.bashrcを追加し、すべての設定を.bashrcに書くこと — これによりログイン方法に関わらず設定が有効になります。
ベストプラクティス: .bash_profileに以下を追加:
if [ -f ~/.bashrc ]; then
source ~/.bashrc
fi
すべてのカスタム設定は.bashrcに書きます。
(5) ▶ サンプル:環境変数の確認と設定
# View environment variables
echo "My home directory is: $HOME"
echo "Current user: $USER"
echo "My Shell: $SHELL"
# Set a temporary variable
export GREETING="Hello from Linux"
echo $GREETING
# Open a new terminal window and check if $GREETING is still there
# Answer: No — temporary variables only exist in the current Shell
出力:
TEXTMy home directory is: /home/alice Current user: alice My Shell: /bin/bash Hello from Linux
(6) ▶ サンプル:PATHを理解する
# View current PATH
echo $PATH | tr ':' '\n' # Display one path per line
# Find which directory ls is loaded from
which ls
# /usr/bin/ls
# What happens if PATH is wrong?
PATH="" # Clear PATH (dangerous!)
ls
# bash: ls: No such file or directory
# Restore PATH
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
出力:
TEXT/usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin /usr/bin/ls
(7) ▶ サンプル:~/scriptsをPATHに追加(永続的)
# Create your own scripts directory
mkdir -p ~/scripts
# Add ~/scripts to PATH (write to .bashrc)
echo 'export PATH="$PATH:$HOME/scripts"' >> ~/.bashrc
> 💡 ヒント:環境変数を永続化するには、`export`コマンドを`~/.bashrc`(または`~/.profile`)に書く必要があります。修正後は`source ~/.bashrc`で即座に反映。そうでなければ新しい設定は新しく開いたターミナルでのみ読み込まれます。
# Reload
source ~/.bashrc
# Verify
echo $PATH | tr ':' '\n' | grep scripts
# /home/alice/scripts
出力:
TEXT/home/alice/scripts
(8) ▶ サンプル:よく使う開発環境変数の設定
# Add the following to ~/.bashrc
# Default editor
export EDITOR=vim
# Locale
export LANG=en_US.UTF-8
# Python development
export PYTHONSTARTUP=~/.pythonrc # Python interactive startup script
export PIP_REQUIRE_VIRTUALENV=true # pip requires virtual environment
# Node.js development
export NODE_ENV=development
export npm_config_prefix=~/.npm-global
# Go development
export GOPATH=$HOME/go
export PATH="$PATH:$GOPATH/bin"
# Your own scripts
export PATH="$PATH:$HOME/scripts"
export PATH="$PATH:$HOME/.local/bin"
出力:
TEXTEDITOR=vim LANG=en_US.UTF-8 PYTHONSTARTUP=/home/alice/.pythonrc PIP_REQUIRE_VIRTUALENV=true NODE_ENV=development GOPATH=/home/alice/go
(9) ▶ サンプル:コマンドが見つかるか確認
# Use which to find the command path
which python3
# /usr/bin/python3
# Use type to check command type (alias/function/builtin/external)
type ls
# ls is an alias for `ls --color=auto'
type cd
# cd is a shell builtin
type node
# node is /usr/bin/node
# Use command -v (most reliable method)
command -v python3
# /usr/bin/python3
出力:
TEXT/usr/bin/python3 ls is an alias for `ls --color=auto' cd is a shell builtin node is /usr/bin/node /usr/bin/python3
(10) ▶ 総合例:「command not found」問題のデバッグ
#!/bin/bash
# debug-path.sh - Debug command-not-found issues
CMD="${1:-http}"
echo "=== 1. What is the command ==="
type "$CMD" 2>/dev/null || echo "type: $CMD not found"
echo ""
echo "=== 2. Which PATH directories contain this command ==="
IFS=':' read -ra PATHS <<< "$PATH"
for dir in "${PATHS[@]}"; do
if [ -f "$dir/$CMD" ]; then
echo "Found: $dir/$CMD"
fi
done
echo ""
echo "=== 3. Global search with find ==="
find /usr /opt $HOME -name "$CMD" -type f 2>/dev/null | head -5
echo ""
echo "=== 4. If found but not in PATH ==="
echo "Run: export PATH=\"\$PATH:/found/directory\""
❓ よくある質問
Q: PATHの順序は重要ですか? A: 非常に重要です!シェルはPATHディレクトリを順番に検索し、最初に一致した時点で停止します。
/usr/local/binが先にあれば、/usr/binより優先されます。新しくインストールしたプログラムが古いバージョンで動く場合は、PATHの順序を確認してください。
Q: 環境変数は再起動後に消えますか? A:
exportで設定した一時変数は再起動後に失われます。永続化するにはexportコマンドをシェル設定ファイル(~/.bashrcや~/.bash_profile)に書く必要があります。
Q:
.bashrcと.bash_profileはどちらが先に実行されますか? A: ログインシェル:/etc/profile→~/.bash_profile→~/.bash_login→~/.profile(前のファイルが存在しない場合)。非ログインシェル:/etc/bash.bashrc→~/.bashrc。
Q: 全ユーザー向けのグローバル環境変数の設定方法は? A:
/etc/environment(単純なキーと値のペア、スクリプト不可)または/etc/profile.d/custom.sh(シェル構文対応、root権限が必要)に書きます。
Q:
printenvとsetの違いは? A:printenvは環境変数(エクスポート済み)のみ表示。setはシェルローカル変数や関数を含むすべての変数を表示。完全な環境確認にはprintenv、スクリプトのデバッグにはsetを使います。
📖 まとめ
- 環境変数はOSレベルのキーと値のペア、子プロセスは親の環境変数を継承
export VAR=valueで設定・エクスポート、unset VARで削除- PATHはコマンド検索パスを定義、順序が優先度を決定
which cmd/type cmdでコマンドの場所を特定- 設定は
~/.bashrc(非ログインシェル)または~/.profile(ログインシェル)に書く - 設定ファイル修正後は
source ~/.bashrcで即座に反映
📝 練習問題
- 基本(難易度 ⭐):現在のPATHを確認(
tr ':' '\n'で1行ずつ表示)、which python3とtype cdでコマンドの種類を理解する - 中級(難易度 ⭐⭐):
~/scriptsディレクトリを作成し、簡単なhello.shスクリプトを書き、PATHに追加して直接実行。.bashrcにEDITOR=vim(またはnano)を設定しsourceで確認する - 上級(難易度 ⭐⭐⭐):コマンド名を引数に取る
debug-path.shスクリプトを作成 — PATHにあるか自動チェック、どのディレクトリに含まれるか確認、PATHにない場合は修正を提案する