「パスを通す」でやっていること(macOS / zsh)
July 26, 2020
*この記事はシェルとして「 zsh」を利用している前提で進めます。macOS Catalina 以降、標準のシェルが「zsh」となったためです(Catalina 以前の OS では「bash」が標準でした)。ただし、この記事において「zsh」と「bash」で違いが出るところはほんの一部分ですので、シェルの種類はあまり気にする必要はありません。
何をやっているか理解した上で作業をしよう #
さて、突然ですが、パスを通す手順は下記の通りです。
- ホームディレクトリ配下に「.zshrc」が存在するか確認する。
- 「.zshrc」が存在すれば次の手順へ、存在しなければ作成してから次の手順へ。
- 「.zshrc」に「export PATH=$PATH:通したいパス」を追記する。
*シェルとして「bash」を利用している場合は、「.zshrc」ファイルではなく「.bash_profile」ファイルになります。
…というのはネットを検索すればいくらでも出てくるのですが、ただし、なぜこれでパスが通るのか、そもそもパスを通すとはどういうことなのか、あいまいにしか理解できていなかったので今回整理してみました。
「export PATH=$PATH:通したいパス」がやっていること #
まず、手順の3番目に出てきた上記が具体的に何をやっているのかを見ていきましょう。
これは export コマンドを使用しています。「export 変数名=値」とすることで、環境変数である「変数名」に「値」を設定することができます。
「export PATH=$PATH:通したいパス」の場合、変数名に該当する部分は「PATH」であり、値に該当する部分は「$PATH:通したいパス」です。つまり、「PATH」という環境変数に、「$PATH:通したいパス」という値を設定する、というのがここでやっていることになります。
環境変数とは #
変数の意味はわかると思いますが、気になるのは、“環境"という部分だと思います。
シェルには2種類の変数があります。それが「シェル変数」と「環境変数」です。2つの違いは変数の有効範囲です。
「シェル変数」はその名の通り、同一シェルの中でのみ有効な変数です。あるシェルの中で「シェル変数」を設定しても、それが使えるのはそのシェルの中のみであり、他のシェルが使用することはできません。
それに対して「環境変数」は、同一のコンピュータ(もしくは同一のユーザ)であれば、どのシェルからも利用することができます。その環境(コンピュータ or ユーザ)内であればどこからでもアクセスできる変数のため、「環境変数」と呼ばれます。
環境変数である「PATH」とは何なのか #
先ほど、『つまり、「PATH」という環境変数に、「$PATH:通したいパス」という値を設定する、というのがここでやっていることになります。』と説明しましたが、「PATH」という環境変数について見ていきます。
ターミナルを開いて「echo $PATH」と入力しましょう。環境変数 PATH の中身を表示することができます。
独自で環境変数を追加していない限り、 mac のデフォルトだと「/user/local/bin:/usr/bin:/bin:/usr/sbin:/sbin」と表示されるはずです。
「:」は区切り文字と捉えてください。そうすると$PATH の中身は「/usr/local/bin」「usr/bin」「/bin」「/usr/sbin」「/sbin」という5つのパスが設定されているということが見て取れます。
これらのパスはシステムがデフォルトで設定しているわけですが、では具体的にどのファイルで設定されているか見てみます。そのファイルは、「/private/etc/」にある「paths」ファイルです。
paths を開いて中身を見てみましょう。
さきほど見た、5つのパスが設定されていることが確認できます。
パスが通っていると何ができるのか #
さて、ここで上記で出てきた5つのパスの1つ「/bin」の中身を見てみましょう。
わかりますでしょうか。シェルで使うコマンドである「ls」の記載が見つかります。他には「mkdir」「pwd」などもありますね。これらはすべて実行ファイルです。右端の種類列を見ると、Unix 実行ファイルと表示されているのが確認できます。コマンドもその実態は普通のファイルにすぎません。
シェルで「ls」や「pwd」といったコマンドを入力した時、このディレクトリに格納されているこれらのファイルが実行されています。つまり「ls」と入力することと、「/bin/ls」と入力することの意味は同じで、どちらも「/bin」配下の「ls」ファイルが実行されます。
「/bin/ls」についてはルートディレクトリから「ls」ファイルまでのパスを記載してファイルを実行しているわけですが、ここで改めて考えると、逆になぜ「ls」と入力しただけでもこのファイルが実行できているのか疑問に感じませんか。
ずばりその答えが、「ls」ファイルが格納されているディレクトリに対してパスが通っているから、ということになるのです。
このように、パスが通っていると、フルパスを入力せずとも、コマンド名(ファイル名)を入力するだけで実行することが可能となります。
つまり、パスを通すということは、毎回フルパスを入力するのを避け、より簡潔にファイルへアクセスできるようにし、効率化するというものなのです。
コマンド実行時、シェルは PATH にあるパスの中身を確認する #
次にポイントとなるのがシェルの動きです。
コマンドを実行したとき、シェルは PATH に指定されているパスの中身を確認し、その中にコマンドで指定されたファイルが存在するかを自動的に確認しています。そこにファイルが存在すれば実行し、存在しなければ「見つからない」というメッセージを表示します。
- 「ls」を実行したときの動き
- 「/usr/local/bin」の中に「ls」ファイルが存在するか確認する
- 存在すれば実行し、なければ次へ
- 「usr/bin」の中に「ls」ファイルが存在するか確認する
- 存在すれば実行し、なければ次へ
- 「/bin」の中に「ls」ファイルが存在するか確認する
- 存在すれば実行し、なければ次へ
- 「/usr/sbin」の中に「ls」ファイルが存在するか確認する
- 存在すれば実行し、なければ次へ
- 「/sbin」の中に「ls」ファイルが存在するか確認する
- 存在すれば実行し、なければ「見つからない」メッセージを表示
- 「/usr/local/bin」の中に「ls」ファイルが存在するか確認する
実際には「/bin」の中に「ls」ファイルが存在しているので、そこでファイルが実行され、それ以降の探索は行われません。
また、例えば「lsls」といった存在しないコマンドを実行(ファイルを指定)した場合は、「/usr/local/bin」「usr/bin」「/bin」「/usr/sbin」「/sbin」を最後まで探索してもファイルは見つけられず、「command not found」のメッセージが返されます。
新たにパスを通す必要性 #
さて、折り返し地点をむかえました。ここからは、自分で用意したファイルにパスを通す過程を通じて、理解を進めていきます。
ホームディレクトリ配下に「shell」ディレクトリを作成し、その中に「hello.sh」というシェルスクリプトを作成しました。このスクリプトには「echo “This is hello shell !!"」と記入されており、実行すると「This is hello shell !!」と表示されます。
上の画像をご覧ください。「hello.sh」とした入力しただけでは「command not found」となってしまいます。フルパスで「/Users/ユーザ名/shell/hello.sh」とすれば実行できますが、毎回フルパスを入力するのは面倒です。
解決策として思い当たるのは、すでにパスが通っているディレクトリ、例えば先ほどの「/bin」に、「hello.sh」を格納してしまう方法です。こうすることで「hello.sh」と入力しただけで実行することは可能ですが、これは控えておきましょう。
デフォルトで用意されているディレクトリには以下の通りそれぞれ役割があり、またシステムにとって重要なディレクトリであるため、慣れないうちは触るのを控えた方が良いです。
- /bin …基本的なコマンド
- /sbin …管理者用コマンド
- /usr/bin …アプリケーション用の基本的なコマンド
- /usr/sbin …アプリケーション用の管理者用コマンド
- /usr/local/bin …追加したアプリ用のコマンド
ということで、素直に「hello.sh」が格納されている「/Users/ユーザ名/shell/」にパスを通すことにします。
パスを通すコマンド #
パスを通すコマンドは「export PATH=$PATH:通したいパス」でしたから、今回の場合は「export PATH=$PATH:/Users/ユーザ名/shell/」とすることで、環境変数である PATH に「:/Users/ユーザ名/shell/」を追加することができます。
ここで、コマンドの中に出てくる「$PATH」とは現在の PATH に登録されている内容を指定しています。つまり、mac のデフォルトの場合だと、最初に「echo $PATH」をした時に表示された「/user/local/bin:/usr/bin:/bin:/usr/sbin:/sbin」を指しています。
要するに以下2つのコマンドはどちらも同じ意味です。
- export PATH=$PATH:/Users/ユーザ名/shell/
- export PATH=/user/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/ユーザ名/shell/
どちらのコマンドを実行しても、その意味は、現在の「export PATH=/user/local/bin:/usr/bin:/bin:/usr/sbin:/sbin」という PATH の内容を、「export PATH=/user/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/ユーザ名/shell/」に上書きするというものになります。
ただし、これはあくまでも PATH の内容が mac のデフォルトのままになっていた場合に限ります。皆さんの方で意図して設定した覚えはなくとも、アプリのインストールなどに合わせて PATH が追加されていた場合、単純に「export PATH=/user/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/ユーザ名/shell/」と直書きしたコマンドで更新するとデフォルト以外の PATH 設定が削除されて上書きされてしまいます。
そのため、安全策として「export PATH=$PATH:/Users/ユーザ名/shell/」という、「$PATH」を使用したパターンで更新した方が良いでしょう。
ターミナルで実行しただけでは一時的にか設定されない #
さっそくターミナルを開いて export コマンドを実行してみます。
export コマンド実行後、「echo $PATH」を実行し PATH の内容を確認したところ、末尾に「:/Users/ユーザ名/shell/」が追加されていることを確認できました。そして「hello.sh」を実行すると、確かに「This is hello shell !!」と表示されます。
しかし、このやり方には問題があります。ターミナルを1度終了したあと、再度開き、「hello.sh」を実行してみます。
そうすると、今度は「hello.sh」の結果が「command not found」となってしまいました。「echo $PATH」で PATH を確認すると、設定内容が戻ってしまっています。
このような結果となってしまうのは、export で設定した内容はそのシェルを開いている最中のみ有効なものであり、終了すると元に戻ってしまうためです。
もう一度 export コマンドを実行すれば再度設定できますが、シェルを開くたびに毎回 export を入力するのは面倒です。
これを解決するのが「.zshrc」ファイルです。
「.zshrc」ファイルを利用する #
*シェルで bash を使っている方は「.zshrc」を「.bash_profile」に読み替えてください。
「.zshrc」はシェルである zsh が起動するときに読み込まれるファイルです。このファイルに書かれている内容は、zsh 起動時に自動で実行されます。
つまり「.zshrc」に export コマンドを書いておくことで、毎回手動で export コマンドを入力せずとも、自動で実行されるようになります。
「.zshrc」はホームディレクトリ配下にありますが、デフォルトでは作られていない場合もあります。その場合は自分で作成します。そして中に export コマンドを記述します。
なお「.zshrc」ファイルは隠しファイルです。mac の Finder では「command + shift + .(ピリオド)」のショートカット で隠しファイルが表示できるので、「.zshrc」が存在するか確かめてください。
これで設定は完了です。
試しに、ターミナル起動直後に「hello.sh」を実行してみます。
うまくいきました!
まとめ #
冒頭に記載した通り、パスを通すために行うことは下記だけです。
- ホームディレクトリ配下に「.zshrc」が存在するか確認する。
- 「.zshrc」が存在すれば次の手順へ、存在しなければ作成してから次の手順へ。
- 「.zshrc」に「export PATH=$PATH:通したいパス」を追記する。
しかし、なぜ上記を行えばパスを通すことができるのか(そもそもパスを通すとはどういう意味なのか)を理解いただけたでしょうか。
この記事は自分用のメモ代わりに書いていたのですが、同じような疑問をお持ちの皆さんのお役に立てましたら嬉しいです。
それでは以上でこの記事を終わります。ありがとうございました。