PATHを通すについてざっくりまとめる
目次
- 目次
- PATHを通すとは
- そもそもシェルの環境変数とは何?
- コマンドサーチパスとは
- なぜcatコマンドをシェルから実行できるのか
- PATHを通すデメリット・メリット
- 実際にPATHを通してみる
- 実際にGoでcatコマンドもどきのコマンドを作ってみて、PATHを通して、コマンド名だけで実行できるようにする
- 終わり
- 参考記事
PATHを通すとは
PATHを通すとは、「シェルの環境変数PATHにコマンドサーチパスを登録する」という意味です
そもそもシェルの環境変数とは何?
シェルの動作(振る舞い)を設定するためには,シェル変数あるいは環境変数に値を設定します。 2つの変数の特徴を以下にまとめます。
シェル変数
- 設定されたシェルでしか参照できない変数
- つまり、シェル変数は子プロセスに引き継がれない
- 変数名に$をつけると参照できる
-
- 設定されたシェルと、シェルで起動したプログラムで参照できる変数
- つまり、環境変数は子プロセスに引き継がれる
- 変数名に$をつけると参照できる
以下はターミナルでの実行例です。 この実行例から、シェル変数と環境変数の違いが分かりました。
# TESTというシェル変数または環境変数を削除する unset TEST # シェル変数TESTを設定する TEST=hoge_fugan # シェル変数を表示する echo $TEST => hoge_fugan # envコマンドは環境変数を一覧で表示するコマンド # 何も出力されないので、TESTが環境変数ではないことが確認できた env | grep TEST # test.shを作成して、そのファイル内で、echo $TESTを書いた cat /tmp/test.sh => echo $TEST # このシェルスクリプトを実行すると何も表示されない # つまり、シェルから起動したプログラムではシェル変数を参照できないことが示せた zsh /tmp/test.sh # シェル変数を消す unset TEST # 環境変数を設定する。 # exportを使えば、環境変数を設定できる export TEST=hoge_fugan # TESTが環境変数であることが分かった env | grep TEST => TEST=hoge_fugan # TESTは環境変数なので、シェルから実行するプログラムで参照できる # そのため、echoコマンドで参照できた zsh /tmp/test.sh => hoge_fugan
コマンドサーチパスとは
コマンドサーチパスとは、シェルがコマンドの実行ファイルを探しに行く際に参照するパスのことです。もっとざっくりいうと、コマンドの実行ファイルの場所を示すパスのことです。
なぜcatコマンドをシェルから実行できるのか
今までlsコマンドやcatコマンドをシェルから実行していました。それらのコマンドが実行できる理由は、それらのコマンドに対応した実行ファイルがmac上のあるディレクトリ配下に存在していて、シェルがいろんなディレクトリ配下を見て、目的の実行ファイルが存在するかを探して実行してくれるためです。
例えば、catコマンドの実行ファイルは、/bin/cat
に存在しています。つまり、catコマンドの実行ファイル(catファイル)は/bin
ディレクトリ配下に存在するということです。
which cat /bin/cat
/binディレクトリ配下のcatファイルは実行ファイル(プログラムをビルドした際に生成されるファイル)なので、シェルにcatファイルの絶対パスを指定すれば、実行できます。
/bin/cat /tmp/test.sh => echo $TEST
catコマンドを実行する際に、/bin/cat
と毎回打つのはめんどくさいです。しかし、私たちは、catコマンドを実行する際に、/bin/cat
なんか打ったことないです。それはなぜかというと、環境変数PATHにコマンドサーチパスの/bin
が既に登録されているからです。
整形前
echo $PATH => /Users/yuuki_haga/.pyenv/shims:/Users/yuuki_haga/.pyenv/bin:/opt/homebrew/opt/openssl@3/bin:/Users/yuuki_haga/.cargo/bin:/usr/local/opt/mysql@5.7/bin:/Users/yuuki_haga/.rbenv/shims:/Users/yuuki_haga/.rbenv/bin:/Users/yuuki_haga/.nodenv/shims:/Users/yuuki_haga/.nodenv/bin:/usr/local/go/bin:/Library/Frameworks/Python.framework/Versions/3.11/bin:/Users/yuuki_haga/.nodebrew/current/bin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin:/Library/Apple/usr/bin:/Users/yuuki_haga/.cargo/bin:/Users/yuuki_haga/exercise:/Users/yuuki_haga/original_command:~/go/bin
整形後(:を改行コードにした)
echo $PATH | tr ":" "\n" => /Users/yuuki_haga/.pyenv/shims /Users/yuuki_haga/.pyenv/bin /opt/homebrew/opt/openssl@3/bin /Users/yuuki_haga/.cargo/bin /usr/local/opt/mysql@5.7/bin /Users/yuuki_haga/.rbenv/shims /Users/yuuki_haga/.rbenv/bin /Users/yuuki_haga/.nodenv/shims /Users/yuuki_haga/.nodenv/bin /usr/local/go/bin /Library/Frameworks/Python.framework/Versions/3.11/bin /Users/yuuki_haga/.nodebrew/current/bin /usr/local/bin /System/Cryptexes/App/usr/bin /usr/bin /bin /usr/sbin /sbin /usr/local/go/bin /Library/Apple/usr/bin /Users/yuuki_haga/.cargo/bin /Users/yuuki_haga/exercise /Users/yuuki_haga/original_command ~/go/bin
環境変数PATHには複数のコマンドサーチパスが登録されています。それらのコマンドサーチパスは:
で区切られています。コマンドを実行しろとユーザーからシェルに対して命令が来たら、シェルは環境変数PATHに登録されているコマンドサーチパスを左から順に見ていって、コマンドサーチパスのディレクトリ配下にコマンドの実行ファイルがないかを探します。そして、コマンドの実行ファイルがあったら、その実行ファイルを実行してくれます。
PATHを通すデメリット・メリット
デメリット
プログラムを実行するのに、プログラムの実行ファイルの絶対パスを指定する必要があります。めんどくさいです
メリット
プログラムをファイル名で実行できるので楽です。
実際にPATHを通してみる
自分の環境には、nodebrewというプログラムが存在します。今回、nodebrewのコマンドサーチパスをわざと消してみて、nodebrewが使えなくなったことを確認してから、PATHを通すとどうなるのかを確認してみます。
# nodebrewコマンドが使えることを確認する nodebrew versions => nodebrew 1.0.1 Usage: nodebrew help Show this message nodebrew install <version> Download and install <version> (from binary) nodebrew compile <version> Download and install <version> (from source) nodebrew install-binary <version> Alias of `install` (For backward compatibility) nodebrew uninstall <version> Uninstall <version> nodebrew use <version> Use <version> nodebrew list List installed versions nodebrew ls Alias for `list` nodebrew ls-remote List remote versions nodebrew ls-all List remote and installed versions nodebrew alias <key> <value> Set alias nodebrew unalias <key> Remove alias nodebrew clean <version> | all Remove source file nodebrew selfupdate Update nodebrew nodebrew migrate-package <version> Install global NPM packages contained in <version> to current version nodebrew exec <version> -- <command> Execute <command> using specified <version> Example: # install nodebrew install v8.9.4 # use a specific version number nodebrew use v8.9.4 # nodebrewの実行ファイルがどこに存在するかを確認する which nodebrew /Users/yuuki_haga/.nodebrew/current/bin/nodebrew # 実際にこのパスをシェルに渡してみて、実行できるか確認する # 実行できた /Users/yuuki_haga/.nodebrew/current/bin/nodebrew versions => nodebrew 1.0.1 Usage: nodebrew help Show this message nodebrew install <version> Download and install <version> (from binary) nodebrew compile <version> Download and install <version> (from source) nodebrew install-binary <version> Alias of `install` (For backward compatibility) nodebrew uninstall <version> Uninstall <version> nodebrew use <version> Use <version> nodebrew list List installed versions nodebrew ls Alias for `list` nodebrew ls-remote List remote versions nodebrew ls-all List remote and installed versions nodebrew alias <key> <value> Set alias nodebrew unalias <key> Remove alias nodebrew clean <version> | all Remove source file nodebrew selfupdate Update nodebrew nodebrew migrate-package <version> Install global NPM packages contained in <version> to current version nodebrew exec <version> -- <command> Execute <command> using specified <version> Example: # install nodebrew install v8.9.4 # use a specific version number nodebrew use v8.9.4 # nodebrewのコマンドサーチパスは、/Users/yuuki_haga/.nodebrew/current/bin/nodebrew # このコマンドサーチパスがどこでPATHに通されたのかをgrepコマンドで確認する # .zprofileファイルでPATHに通されたことを確認できた grep -r ".nodebrew" ~/ /Users/yuuki_haga//.fig.dotfiles.bak/2022-12-28_02-28-08/.zprofile:export PATH=$HOME/.nodebrew/current/bin:$PATH # vim ~/.zprofileを確認して、以下の行をコメントアウトした # export PATH=$HOME/.nodebrew/current/bin:$PATH # sourceで変更をシェルに反映する source ~/.zprofile # コマンドの実行結果が何も返ってこないので、nodebrewに関するコマンドサーチパスが環境変数ATHから消えた echo $PATH | grep nodebrew # nodebrewへのコマンドサーチパスを環境変数PATHから消したので、シェルがコマンド名から、実行ファイル名を探すことができない。 # そのため、コマンドの実行ファイル名を用いて、コマンドを実行することができない。 nodebrew zsh: command not found: nodebrew # nodebrewのコマンドサーチパスを環境変数PATHに登録していないので、nodebrewがどこにあるのかわからんとシェルから返答が来ている which nodebrew nodebrew not found # しかし、ホスト上に実行ファイル自体は存在するので、nodebrewを実行することはできる。 /Users/yuuki_haga/.nodebrew/current/bin/nodebrew versions => nodebrew 1.0.1 Usage: nodebrew help Show this message nodebrew install <version> Download and install <version> (from binary) nodebrew compile <version> Download and install <version> (from source) nodebrew install-binary <version> Alias of `install` (For backward compatibility) nodebrew uninstall <version> Uninstall <version> nodebrew use <version> Use <version> nodebrew list List installed versions nodebrew ls Alias for `list` nodebrew ls-remote List remote versions nodebrew ls-all List remote and installed versions nodebrew alias <key> <value> Set alias nodebrew unalias <key> Remove alias nodebrew clean <version> | all Remove source file nodebrew selfupdate Update nodebrew nodebrew migrate-package <version> Install global NPM packages contained in <version> to current version nodebrew exec <version> -- <command> Execute <command> using specified <version> Example: # install nodebrew install v8.9.4 # use a specific version number nodebrew use v8.9.4 # だけど、毎回こんな長いパスをシェルに指定するのはめんどくさい。なのでこの実行ファイル(nodebrew)へのコマンドサーチパスをPATHに登録する(PATHに通す) # ~/.zshrcに登録する # nodebrewが存在するディレクトリまでをPATHに登録する # echo $PATH:$HOME/.nodebrew/current/bin/でどんなパスになるか事前に確認しておく export PATH=$PATH:$HOME/.nodebrew/current/bin/ # シェルに変更を反映する source ~/.zshrc # 無事PATHにnodebrewへのコマンドサーチパスが登録されたことを確認できた(PATHが通された) which nodebrew => /Users/yuuki_haga/.nodebrew/current/bin//nodebrew echo $PATH | grep nodebrew => /Users/yuuki_haga/.pyenv/shims:/Users/yuuki_haga/.pyenv/bin:/opt/homebrew/opt/openssl@3/bin:/Users/yuuki_haga/.cargo/bin:/usr/local/opt/mysql@5.7/bin:/Users/yuuki_haga/.rbenv/shims:/Users/yuuki_haga/.rbenv/bin:/Users/yuuki_haga/.nodenv/shims:/Users/yuuki_haga/.nodenv/bin:/usr/local/go/bin:/Users/yuuki_haga/.pyenv/bin:/opt/homebrew/opt/openssl@3/bin:/Users/yuuki_haga/.cargo/bin:/usr/local/opt/mysql@5.7/bin:/Users/yuuki_haga/.rbenv/shims:/Users/yuuki_haga/.rbenv/bin:/Users/yuuki_haga/.nodenv/shims:/Users/yuuki_haga/.nodenv/bin:/usr/local/go/bin:/Library/Frameworks/Python.framework/Versions/3.11/bin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin:/Library/Apple/usr/bin:/Users/yuuki_haga/.cargo/bin:/Users/yuuki_haga/exercise:/Users/yuuki_haga/original_command:~/go/bin:/Users/yuuki_haga/exercise:/Users/yuuki_haga/original_command:~/go/bin:/Users/yuuki_haga/.nodebrew/current/bin/ nodebrew versions => nodebrew 1.0.1 Usage: nodebrew help Show this message nodebrew install <version> Download and install <version> (from binary) nodebrew compile <version> Download and install <version> (from source) nodebrew install-binary <version> Alias of `install` (For backward compatibility) nodebrew uninstall <version> Uninstall <version> nodebrew use <version> Use <version> nodebrew list List installed versions nodebrew ls Alias for `list` nodebrew ls-remote List remote versions nodebrew ls-all List remote and installed versions nodebrew alias <key> <value> Set alias nodebrew unalias <key> Remove alias nodebrew clean <version> | all Remove source file nodebrew selfupdate Update nodebrew nodebrew migrate-package <version> Install global NPM packages contained in <version> to current version nodebrew exec <version> -- <command> Execute <command> using specified <version> Example: # install nodebrew install v8.9.4 # use a specific version number nodebrew use v8.9.4
実際にGoでcatコマンドもどきのコマンドを作ってみて、PATHを通して、コマンド名だけで実行できるようにする
catコマンドもどきのhenacatコマンドをGoで作りました。
cat README.md => # henacat% # catコマンドと同じように、パスを指定するとファイルの内容を出力できる ./henacat README.md => # henacat # henacatというコマンドの実行ファイルは以下のディレクトリ配下に存在する pwd => /Users/yuuki_haga/repos/go/cli/bin # 実行ファイルは存在するけど、コマンドサーチパスを環境変数PATHに登録していないので、 # 当たり前だけどコマンド名だけでは、シェルは実行ファイルを見つけられない which henacat => henacat not found #コマンド名だけで実行するには、以下の3つの方法が考えられる # 1. 既にあるコマンドサーチパスのディレクトリにプログラムを移動させる(無駄にパスを通さなくても済むが、プログラムの移動がめんどい) # 2. プログラムがいるディレクトリのコマンドサーチパスを環境変数PATHに登録する(プログラムを動かさなくて済むが、パスを通す必要がある) # 3. すでにPATHが通っているディレクトリに、実行ファイルへのシンボリックリンクを貼る(プログラムを動かさなくて済むし、パスを追加で通す必要もないが、シンボリックリンクを貼る必要がある) # 1の場合 # /usr/local/go/bin配下にプログラムをコピーする sudo cp ./henacat /usr/local/go/bin/henacat which henacat # できた /usr/local/go/bin/henacat # 2の場合 export PATH=$PATH:$HOME/repos/go/cli/bin/ source ~/.zshrc which henacat # できた => /Users/yuuki_haga/repos/go/cli/bin//henacat # 3の場合 # シンボリックリンクはショートカットファイルのようなもの # /usr/local/go/bin/配下にhenacatというシンボリックリンクを作成した # このシンボリックリンクを実行しようとすると、go/cli/bin/henacatが実行される # シンボリックリンクの構文は、ln -s <リンク対象のファイルまたはフォルダのパス> <作成するリンクのパス> sudo ln -s /Users/yuuki_haga/repos/go/cli/bin/henacat /usr/local/go/bin/henacat which henacat # できた => /usr/local/go/bin/henacat ll /usr/local/go/bin => total 37200 drwxr-xr-x 5 root wheel 160 9 4 02:35 . drwxr-xr-x 17 root wheel 544 4 27 00:57 .. -rwxr-xr-x 1 root wheel 15610192 4 27 01:01 go -rwxr-xr-x 1 root wheel 3429776 4 27 01:01 gofmt lrwxr-xr-x 1 root wheel 42 9 4 02:35 henacat -> /Users/yuuki_haga/repos/go/cli/bin/henacat
終わり
PATHを通すって聞くと、環境変数PATHにコマンドサーチパスを登録するイメージでしたが、調べてみると、既存のコマンドサーチパスをうまく利用するやり方(プログラム側を動かしたり、シンボリックリンクを貼ったり)でもコマンドを実行できるので、いろんなやり方があって面白いなと思いました。
参考記事
PATHを通すとは? (Mac OS X) #初心者 - Qiita
シェル変数や環境変数を削除するコマンド #Linux - Qiita
シェル変数と環境変数の違いをコマンドラインで確認する #Linux - Qiita
シェルの基本操作法(後編3:シェル変数と環境変数) | 日経クロステック(xTECH)
シェル変数と環境変数とコマンドの先頭で指定する変数の違いについて - Linux - このすみノート
【export】Linuxで環境変数を設定・削除するコマンド | UX MILK