「パスを通す」とは何ぞや
「パスを通す」とは特定のプログラムを「プログラムの名前だけで実行できるように道を示すこと」です。
...どういうことじゃい?ということで、お馴染みの「git」というコマンドを例にその意味を解釈してみます。
「gitにパスが通っている」とは、「git」という名前を打てば/usr/bin/
ディレクトリにあるgit
ファイルを実行できるように道が示されているという意味になります。図解にもしましたが、パスの通ったコマンドの処理の流れは下記のようなイメージです。
git status
とCLIで打たれるgit
という実行ファイルのあるパスをPATH
という環境変数を頼りに探す/usr/bin/
というパスの中にgit
という実行ファイルが見つかるgit
ファイルを解析してgit status
という指示を実行する
ちなみに/usr/bin/git status
とCLIに打ってもgit status
と全く同じ実行ができます。つまり、パスを通せば、「本来なら/usr/bin/git status
とフルパスで実行ファイルを打たないといけないところ、git status
と楽に実行ができる」ということになります。
念の為、Linuxの資格でもお馴染みの「Linuc」の言葉の引用も参照しておきます。
シェルが探しに行くディレクトリを設定する作業を、「パスを通す」と言います。正確には「コマンドサーチパス」、すなわちコマンドを探しにいくパスの設定をする、ということですね。
Linux豆知識 019 パスを通す|Linuc
つまるところパスを通すとは「プログラムの実行ファイルを探しやすいように道を示してあげる」という言い方ができるかと思います。
環境変数PATH
とは何だい
では、PATH
とは何か。PATH
とはコマンド探索のためのパス格納庫のようなものです。CLIで簡単にその実態は確認できます。
$ printenv PATH
# /user/.nodenv/shims:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin:~/.docker/bin
printenv
とは、引数に環境変数を設定することでその環境変数を表示できるコマンドです。(LinuCレベル1 101試験の例題と解説 1.03.1 コマンドラインの操作)
もちろん実行結果は人によって異なりますが...ちょっと1行で返されて見づらいので、パス毎に改行してみます。
/Users/***/.nodenv/shims:
/usr/local/bin:
/System/Cryptexes/App/usr/bin:
/usr/bin:
/bin:
/usr/sbin:
/sbin:
/opt/homebrew/bin:
~/.docker/bin
なるほど、:
で複数のパスを区切っていたわけですね。そして、このPATH
をコマンド探索時にどのように活用しているか。再びgit
を例にして見てみます。
/Users/***/.nodenv/shims:
にgit
あるか? -> No./usr/local/bin/:
にgit
あるか? -> Yes!/usr/bin/git
を実行
このように、(Linuxでは)PATH
の先頭から順番にgit
という実行ファイルがあるかどうか探索していって、見つかった段階でそのパスの中にあるgit
ファイルを実行しています。
PATHの優先度について|Linux豆知識 019 パスを通す|Linuc
ちなみに、which git
と打てば環境変数PATH
に基づいてそのコマンドの絶対パスを返してくれますよ。
$ which git
# /usr/bin/git
パスを通す方法
少しずつ実態が見えてきたところで、パスの通し方の解説です。結局パスを通すというのは、環境変数PATH
を上書きしているだけです。実例を見てみましょう。
$ export PATH="/opt/hello/bin/:$PATH"
export
は環境変数をセットするコマンドで、$PATH
はもちろん環境変数PATH
自身を参照します。つまり、/opt/hello/bin/:(と元々のPATH)
という文字列をPATH
に再代入しているだけということ。
まとめると、環境変数PATH
とはコマンド探索をする時に活用するパスの格納庫であり、そのPATH
をexport
で更新すれば新たなパスを通すことができる。という訳です。
環境変数とは?変数との違いは?
この記事は「なんとなく理解」の禁止条例を出している(?)ので、環境変数もちゃんと理解していきます。
変数とはシェル上からだけ参照できる値のことで、環境変数とはシェルだけではなくシェルから起動された他のプログラムからも参照できる値となります。
...ん〜分かりづらいですね!CLIで実際に試してみます。
$ test="変数っす"
# `変数名=値`と直接入力すればOK
$ export TEST="環境変数でございます"
# 環境変数は`export`コマンドで挿入可能
$ echo $test
# 変数っす
$ echo $TEST
# 環境変数でございます
まずはこれが変数と環境変数の設定方法です。ちなみに$
は「変数を取り出す」という役割があります。仮にecho test
と叩いてもtest
と返すだけなのでご注意を。
肝心の参照できる範囲ですが、例えば、hello
という実行ファイルに下記が書かれていたとします。
#!/bin/bash
echo "hello $TEST"
このhello
というファイルを実行すると、hello 環境変数でございます
と返すことができます。でも下記だと実行してもhello
としか返してくれず変数は参照できません。
#!/bin/bash
echo "hello $test"
つまり、環境変数ならプログラムの中からも参照できるけど、変数だとシェル上からしか参照できないという事です。
【実践!】自分で実行ファイルを作ってパスを通してみる
ここまでの説明で以下のことが分かりました。
- 「パスを通す」とは何か
- 環境変数
PATH
の真相と設定方法 - ついでに
printenv
とwhich
コマンドの使い方
百聞は一見に如かずということで、簡単な実行ファイルを自作してパスを通して見ましょう!(作ってワクワク)
要件
## 概要
`hello [引数]`と打てば`Hey [引数] !`と返してくれる`hello`コマンド
例)
$ hello world
# Hey world!
## 詳細
* `~/Documents/path-learning/usr/local/bin`ディレクリの中に実行ファイルを配置
* フルパスじゃなく`hello`コマンドを打つだけで実行できるようにパスを通す
* シェルは`bash`を使う
ザックリと要件はこんなところです。僕も実際に試しましたが、全然簡単でした♪
さぁやって見ましょう!
ステップ1/3:実行ファイルを作成
せっかくなのでFinder等のGUIは使わずにCLIの真っ黒の画面だけでやってみます!
$ mkdir -p ~/Documents/path-learning/usr/local/bin
# ディレクトリの作成。`-p`で中間ディレクトリが無い場合も同時に作成可能
$ cd ~/Documents/path-learning/usr/local/bin
# 移動
$ vim hello
# `hello`というファイル作成
次にhello
実行ファイルの中身を作成。
#!/bin/bash
echo "Hey $1!"
# vimエディタを使う場合、キーボードで`i`を打てば入力モードになります。入力ができたら`esc`を押してから`:wq`と入力すれば保存して閉じることが可能。
# `echo`は文字列の出力
# `$1`は第1引数の取り出し(`hello World`の場合は`World`=`$1`となる
保存して閉じたら、この実行ファイルが使えるかどうか、一度下記のコマンドを打って見ましょう!
$ ~/Documents/path-learning/usr/local/bin/hello World
# zsh: permission denied: /Users/***/Documents/path-learning/usr/local/bin/hello
何やらパーミッションエラーが出ました。/Users/***/Documents/path-learning/usr/local/bin/hello
このファイルには実行可能な権限が付与されていませんよ。と言われています。hello
を実行ファイルとして扱うためには、権限の付与が必要になります。
ステップ2/3:実行権限(execute permission)を付与
chmod
(change modeの略)というコマンドを使えばファイルやディレクトリにアクセス権限を付与できます。実行権限(execute permission)を付与するには+x
というオプションをつけます。ちなみに権限削除は-x
。
$ chmod +x ~/Documents/path-learning/usr/local/bin/hello
これで一度hello
の実行ファイルを呼び出して見ましょう!
$ ~/Documents/path-learning/usr/local/bin/hello World
# Hey World!
作ったシェルスクリプト通りに文字列が出力がされました!...と言っても毎回~/Documents/path-learning/usr/local/bin/hello
こんな長いパスを打つのは面倒ですね。試しにhello World
と打って見ましょう。
$ hello World
# zsh: command not found: hello
環境変数PATHについての理解があれば、なぜnot found
かお分かりかと!では本題のパスを通して見ましょう...!
ステップ3/3:パスを通す
$ export PATH="$HOME/Documents/path-learning/usr/local/bin/:$PATH"
この1行に本題の全てが詰まっています。順に説明していきますね。
export
コマンドを使ってPATH
という環境変数を設定$HOME
はホームディレクトリが代入された環境変数(【Linux】/と~の違い(ルートディレクトリとホームディレクトリの違い))$PATH
はもちろん環境変数PATH
自身のこと
つまり下記の操作をしています。
$ export PATH="$HOME/Documents/path-learning/usr/local/bin/:$PATH"
# `PATH`に、`~/Documents/path-learning/usr/local/bin/:(の後ろに元々のPATH)`という文字列を環境変数として再代入
これでパスを通せたので、試して見ましょう!
$ hello World
# Hey World!
無事にhello
コマンドだけで実行できました!
【応用】要件の追加
ここからは実務でありそうな応用編です。先輩から下記のような指示があったとします。
~/Documents/path-learning/usr/local/bin/jp/
の中にやぁ $1!
と日本語で返す実行ファイルも追加したので、今後はそっちにパスを通し直してください〜。
「パスを通し直す」「パスの向きを変える」...おぉ、なんだかこの言葉の意味が今まで以上に鮮明に理解できるではありませんか!!
テンションもぶち上がったところで、実務っぽく現在のパスの向きを確認しつつ進めていきましょう。
$ which hello
# /Users/***/Documents/path-learning/usr/local/bin//hello
$ export PATH="$HOME/Documents/path-learning/usr/local/bin/jp/:$PATH"
$ hello 世界
# やぁ 世界!
初めに現在のパスの向きをwhich
コマンドで確かめて、次にexport
で環境変数PATH
の先頭に新たなパスを追加しています。これで.../jp/hello
の実行ファイルにパスの向きを変えることができました!
余談(なんとなく理解を禁止した経緯)
ぼくはWebフロントエンドエンジニアなんですが、社会人1年目の頃にベテランエンジニアにこんなセリフを言われたことがあります。
export PATH="***"
でパスを通す「おまじない」をすればいい...?「おまじない」って何ですか?え、そもそもパスを通すって何か理解できてる?..........うん、できてなさそうやね。この機会にちゃんと理解しましょ。ちなみにクラークによると魔法を使えるのは優れた技術力を持つ人だけですよ。軽はずみに「おまじない」で事を片付けない方がいいっすよ。
そのベテラン先輩は、ぱっと見冷たく見えるけど初心者にもめっちゃ向き合ってくれる神みたいな人でした。ぼくはこの時に「パスを通す」に限らず、なんとなくの理解で「おまじない」と言って暗記したコマンドを打つのはダメだと学びました。
そんな経験もあって、「なんとなく理解禁止」というシリーズでReactやJavaScriptなどの基礎をブログで少しずつ発信しています!
ちなみにクラークの件は、SF作家アーサー・C・クラークが定義したクラークの三原則のひとつに下記の原則があって...
十分に発達した科学技術は、魔法と見分けがつかない。
Any sufficiently advanced technology is indistinguishable from magic.
これになぞられたセリフでした。「十分な技術力を身につければ魔法のような技を出せるだろうけど、初心者のうちはそんな魔法(おまじない)は使えないでしょ」って事でしょうか。それからこのクラークの三原則の言葉が大好きになりました。ぼくも魔法使いになりたい🧙