「インストールしたはずのコマンドがcommand not foundになる」「PATHを通すってどういう意味?」——Linuxを使い始めると必ずぶつかるのが、環境変数とPATHです。環境変数は「シェルやプログラムが参照する設定値」で、その代表格のPATHは「コマンドを探しに行くディレクトリの一覧」です。
つまずきやすいのは、exportを付けない変数は、そこから起動したプログラム(子プロセス)に引き継がれないことと、ターミナルで設定した変数は閉じると消える(永続化には.bashrcが必要)ことです。この記事では、実機のLinux(WSLのDebian)でcommand not foundを実際に再現し、PATHを通して解決するまでを実演しながら整理します。
- 環境変数は
export 名前=値で設定します。exportが無いと子プロセスに渡りません。 - PATHはコロン区切りのディレクトリ一覧。コマンドはここから探されます。
- 「PATHを通す」=
export PATH="$PATH:追加したいディレクトリ"です。 - ターミナルを閉じると消えるため、恒久設定は
~/.bashrcに書きます。 - 確認は
echo $PATH・env・which コマンド名。 VAR=値 コマンドと前置きすると、そのコマンド1回だけ有効にできます。
コマンドの実行に必要な権限はchmod(+xで実行権限)、設定ファイルの編集後の確認はgrep、ほかの基本はよく使うLinuxコマンドまとめもあわせて参考になります。
環境変数とは・exportの意味
環境変数は名前=値の形で設定し、$名前で参照します。重要なのはexportの有無です。exportを付けて初めて、そのシェルから起動するプログラムに引き継がれます。
# ただの代入(シェル変数): このシェルの中だけ MY_VAR="hello" echo $MY_VAR # hello(自分では見える) bash -c 'echo $MY_VAR' # (空)← 子プロセスには渡らない! # export すると環境変数になり、子プロセスにも渡る export MY_VAR bash -c 'echo $MY_VAR' # hello # 定義と export を同時に export API_KEY="abc123"
実機で確認したところ、MY_VAR="hello"と代入しただけの状態では、そこから起動した子プロセス(bash -c)で$MY_VARは空でした。export MY_VARを実行したあとは、子プロセスでもhelloが見えるようになりました。exportの無い変数は「シェル変数」で、そのシェルの中だけの存在です。プログラム(Node.js・Python・各種ツール)から参照させたい設定値は、必ずexportを付けてください。「スクリプトの中では見えるのに、そこから呼んだプログラムには渡っていない」というトラブルは、ほぼこのexport忘れが原因です。設定済みの環境変数の一覧はenvコマンドで確認でき、exportした変数だけがそこに載ります。
PATHの仕組み
PATHは環境変数の中でも特別に重要で、「コマンド名だけで実行されたとき、実体をどのディレクトリから探すか」の一覧です。コロン(:)区切りで複数のディレクトリが並んでいます。
# PATH の中身を見る(コロン区切りのディレクトリ一覧) echo $PATH # /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:... # コマンドの実体がどこにあるかを調べる which ls # /usr/bin/ls など which python3 # /usr/bin/python3 # ls と打つと、PATH のディレクトリを左から順に探して # 最初に見つかった実体が実行される
実機でも、echo $PATHで/usr/local/sbin:/usr/local/bin:...というコロン区切りの一覧が確認できました。lsやpython3とコマンド名だけ打てるのは、シェルがPATHのディレクトリを左から順に探して実体を見つけてくれるからです。which コマンド名を使うと、実際にどこの実体が使われるかが分かります。逆に言えば、PATHに含まれないディレクトリにあるプログラムは、名前だけでは実行できません。これが次のcommand not foundの正体です。
command not found をPATHで解決する(実演)
「インストールしたのにcommand not found」の典型パターンを、実際に再現して解決してみます。実体はあるのにPATHに載っていないのが原因です。
# 自作コマンドを PATH 外のディレクトリに置く mkdir -p ~/mybin echo '#!/bin/bash echo "hello from mybin"' > ~/mybin/hello-cmd chmod +x ~/mybin/hello-cmd # 名前だけで実行 → 見つからない hello-cmd # bash: hello-cmd: command not found # PATH にディレクトリを追加(既存の PATH の後ろに足す) export PATH="$PATH:~/mybin" # もう一度実行 → 動く! hello-cmd # hello from mybin
実機でも、PATH外に置いた自作コマンドはcommand not foundになり、export PATH="$PATH:ディレクトリ"でPATHに追加した直後から名前だけで実行できるようになりました(whichでも追加したディレクトリの実体が表示されました)。これが「PATHを通す」の意味のすべてです。ポイントは"$PATH:追加分"のように既存のPATHを含めて書くことです。export PATH="~/mybin"のように上書きしてしまうと、lsすら見つからなくなります。なお、実体には実行権限(chmod +x)も必要です。
永続化する(~/.bashrc)
注意したいのは、ターミナルでexportした変数は、そのターミナルを閉じると消えることです。次回以降も有効にするには、シェルの設定ファイル~/.bashrcに書いておきます。
# ~/.bashrc の末尾に追記する echo 'export PATH="$PATH:$HOME/mybin"' >> ~/.bashrc # 今開いているターミナルに反映するには source source ~/.bashrc # 以後、新しいターミナルでも自動で PATH が通っている
ターミナルでのexportは、そのシェルのセッション限りです。閉じたり新しいタブを開いたりすると設定は消えています。「昨日通したはずのPATHがまた通っていない」というのは、これが原因です。恒久化するには、~/.bashrc(bashの場合。zshなら~/.zshrc)にexport行を書いておきます。.bashrcはシェルの起動時に毎回読み込まれるため、以後は自動で設定されます。書いた直後の今のターミナルに反映したいときはsource ~/.bashrcで読み込み直します。追記には上書きの>ではなく追記の>>を使うことにも注意してください(>だと.bashrcの中身が全部消えます)。
一時的な指定(前置き)と確認コマンド
環境変数をそのコマンド1回だけ有効にしたいときは、コマンドの前にVAR=値を置きます。また、設定の確認にはenv・echo・whichを使い分けます。
# コマンドの前に置くと、その実行時だけ有効 NODE_ENV=production node app.js # 実行後、シェルには残らない echo $NODE_ENV # (空) # 確認コマンドの使い分け env # export 済みの環境変数を一覧 echo $PATH # 特定の変数の値を表示 which コマンド名 # コマンドの実体の場所
実機でも、TMP_ONLY=abc bash -c 'echo $TMP_ONLY'はそのコマンド内でだけabcが見え、実行後のシェルでは空のままでした。この前置き方式は「1回だけ環境を変えて実行したい」とき(本番モードでの起動テストなど)に便利で、シェルを汚しません。env | grep 名前とすれば、目的の変数が設定されているかをすぐ確認できます。
主なコマンド・書き方一覧
環境変数とPATHの操作をまとめます。
| 書き方 | 働き |
|---|---|
export VAR=値 |
環境変数を設定(子プロセスに渡る) |
VAR=値(exportなし) |
シェル変数(子プロセスに渡らない) |
echo $VAR |
値の確認 |
env |
環境変数の一覧 |
export PATH="$PATH:追加" |
PATHを通す |
which コマンド |
実体の場所を確認 |
~/.bashrc に追記 + source |
永続化と反映 |
VAR=値 コマンド |
1回だけの一時指定 |
よくある失敗
exportを忘れてプログラムに渡らない
代入だけではシェル変数です。プログラムから参照させるにはexportを付けます。
PATHを上書きしてlsまで動かなくなる
export PATH="$PATH:追加分"のように、必ず既存の$PATHを含めます。
ターミナルを閉じて設定が消える
exportはセッション限りです。恒久設定は~/.bashrcに書きます。
.bashrcに書いたのに反映されない
既存のターミナルには自動反映されません。source ~/.bashrcを実行します。
>で.bashrcを上書きしてしまう
追記は>>です。>を使うと設定ファイルの中身が消えます。
よくある質問
export PATH="$PATH:追加したいディレクトリ"と書きます。PATHに載っていれば、コマンド名だけで実行できるようになります。実機でも、command not foundだった自作コマンドが、PATH追加直後に実行できるようになることを確認しています。exportの無い代入はシェル変数で、自分のシェル内でしか見えません。実機でも、export前は子プロセスで空・export後は値が見えることを確認しています。プログラムに渡す設定値には必ずexportを付けてください。exportは、そのセッション限りだからです。恒久的に設定するには、~/.bashrc(zshなら~/.zshrc)にexport行を追記してください。シェルの起動時に毎回読み込まれるため、以後は自動で設定されます。今のターミナルに反映するにはsource ~/.bashrcです。findで探す)、export PATH="$PATH:そのディレクトリ"でPATHに追加します。恒久化するなら~/.bashrcに書いてください。実体に実行権限(chmod +x)があることも確認しましょう。VAR=値を置きます。NODE_ENV=production node app.jsのように書くと、その実行時だけ有効で、シェルには残りません。設定を汚さずに動作を試したいときに便利です。まとめ
- 環境変数は
export VAR=値。exportが無いと子プロセスに渡りません。 - PATHはコマンドを探すディレクトリの一覧(コロン区切り)。
- 「PATHを通す」=
export PATH="$PATH:追加分"(既存PATHを必ず含める)。 - 永続化は
~/.bashrcに追記(>>で)+sourceで反映。 - 確認は
env・echo $VAR・which、一時指定は前置きVAR=値 コマンド。
環境変数とPATHは、Linuxの「コマンドが動く仕組み」の根っこです。「exportしないと渡らない」「PATHは既存を含めて追記」「恒久化は.bashrc」の3点を押さえれば、command not foundにも設定が消える問題にも、自信を持って対処できます。
