Help us understand the problem. What is going on with this article?

環境変数の設定を間違えてほとんどのコマンドが "command not found" になってしまったときの対処法

More than 3 years have passed since last update.

はじめに

先日、サーバの設定をいじっていたときにやらかしてしまい冷汗を書いたので、いざというときに焦らずに対処できるようにするためにここにメモしておきます。

原因

自分の中で得られた結論を先に言ってしまうと、環境変数のexportは複数箇所に書くべきではないです。

.bash_profile等にexport PATH="パス"を追加することで環境変数が使えるようになります。たとえばlsコマンドは本来なら/bin/ls/usr/bin/lsとしなければ実行できませんが、/bin/usr/binを環境変数として登録しておけば単にlsと打つだけで実行できるようになります。

今回の問題の原因は、export PATH="/path/to/something:/path/to/anything:$PATH"となっている行の下にexport PATH="/path/to/badthing"を追加してしまったことです。PATHへの代入が複数ある場合は下に書いた代入文によって上書きされます(プログラムを書くときと同じです)。なので、今回の例だと/path/to/badthingにしかパスが通っていない状態となり、ほとんどのコマンドが環境変数から参照できなくなりました...(これが"/path/to/thing:$PATH"とかならまだ良かったんですがね...)

$ source ~/.bashrc
-bash: rbenv: command not found
$ vi ~/.bashrc
-bash: vi: command not found
$ ls -a
-bash: ls: command not found

パスが通っていないのなら、絶対パスから参照すればいいんだ! とひらめきコマンドのパスを確認しようとするも...

$ which vi
-bash: which: command not found

( ̄△ ̄;)

解決法

このサーバだけではもう手の打ちようがないので、同じOSのテストサーバで確認しました。

$ which vi
/usr/bin/vi

ということで、viの絶対パスは/usr/bin/viということがわかりました。CentOSでもUbuntuでも同じでした。

パスがわかったところで再び問題発生中のサーバに戻りviを起動

$ /usr/bin/vi ~/.bashrc

そして、パスを一行にまとめます。

~/.bashrc
export PATH="/path/to/something:/path/to/anything:/path/to/goodthing:$PATH"

パスは左から順に参照していきますので、たとえばlsの場合、/path/to/something/lsがなければ/path/to/anything/lsを調べ、それがなければ/path/to/goodthing/lsを調べ、それもなければ$PATHにあるパスを調べていきます。

ちなみにパス一覧は以下のコマンドで確認できます。

$ echo $PATH
/path/to/something:/path/to/anything:/path/to/goodthing:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

また、ホームディレクトリ内のディレクトリをパスに指定したい場合は$HOMEを使用することで$HOMEの箇所がホームディレクトリまでのパスとして認識されます。

# $HOME/.binはホームディレクトリ以下の.binディレクトリを参照する
export PATH="$HOME/.bin:/path/to/something:/path/to/anything:/path/to/goodthing:$PATH"

環境変数を正しく設定できたので再読込しようとします。ところが...

$ source ~/.bashrc
-bash: env: command not found

となり再読込もできませんでした。この場合、sourceコマンドは利用できますが、内部的に使用されている(?)envコマンドのパスが通っていないので実行できませんでした。

どうしたものかと少し悩みましたが、そういえば.bashrcの中身はsourceコマンドを使わなくてもシェルに再接続すれば新しい設定で読み込まれるので、一旦切断してしまえばいいことに気づきました。

ローカルの場合はシェルの終了、リモートの場合はSSHのコネクションを切断します。いずれにしても

$ exit

として、再びログインすることで.bashrcの中身が新しく読み込まれます。これで設定が間違っていなければちゃんと元に戻ります。

$ which vi
/usr/bin/vi
$ ls
file1 file2 file3 file4 file5

めでたしめでたし:smile:

結論

繰り返しになりますが、パスは一行にまとめるのがベターです。一行にまとめなくても

export PATH="/path/to/something:/path/to/anything:$PATH"
export PATH="/path/to/anotherthing:$PATH"

となっていれば、2行目の$PATHは1行目のパスの内容を参照するので、この記事のような問題は発生しませんが、冗長的ですし思わぬところでミスをしてしまう可能性があります。

サイトの説明によっては

$ echo 'export PATH="/path/to/something:$PATH"' >> ~/.bashrc

などと書かれていることがあり(現に自分が他の記事で使っています...)一行でまとめておくのはめんどうかもしれませんが、せめて本番サーバ等ではそうしておくほうが無難かな、と今回の反省を踏まえて感じました。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした