如何將目錄加入 PATH
原文由 Julia Evans 于 發布,訂閱此部落格
今天我和朋友聊到如何將目錄加入 PATH。這對長年使用終端機的我來說,感覺是件「理所當然」的事,但當我實際去搜尋操作說明時,卻發現根本找不到把所有步驟都講清楚的教學——很多文章只寫「把這行加到 ~/.bashrc」,但如果你根本不是用 bash 呢?如果你的 bash 設定檔其實在別的地方呢?而且,你到底該怎麼知道要加哪一個目錄?
所以我想試著寫一份更完整的說明,也順便提一下這些年來我踩過的一些坑。
步驟 1:你正在使用哪一種 shell?
如果你不確定自己用的是哪一種 shell,可以用這個方法來確認。執行以下指令:
ps -p $$ -o pid,comm=- 如果你用的是 bash,它會印出
97295 bash - 如果你用的是 zsh,它會印出
97295 zsh - 如果你用的是 fish,它會顯示類似「In fish, please use $fish_pid」的錯誤(
$$在 fish 裡不是合法語法,不過光是看到這個錯誤訊息,就代表你用的是 fish,這點你大概本來就知道了)
另外,bash 是 Linux 上的預設 shell,而 zsh 是 Mac OS 上的預設 shell(以 2024 年為準)。這份說明只會涵蓋 bash、zsh 和 fish。
步驟 2:找到你的 shell 設定檔
- 在 zsh 裡,通常是
~/.zshrc - 在 bash 裡,可能是
~/.bashrc,但情況有點複雜,請見下一節的說明 - 在 fish 裡,通常是
~/.config/fish/config.fish(如果你想百分之百確定,可以執行echo $__fish_config_dir)
關於 bash 設定檔的補充說明
Bash 有三個可能的設定檔:~/.bashrc、~/.bash_profile 和 ~/.profile。
如果你不確定你的系統實際上是用哪一個,我會建議用這個方法來測試:
- 在你的
~/.bashrc中加入echo hi there - 重新啟動終端機
- 如果你看到「hi there」,就代表正在使用
~/.bashrc!太好了! - 如果沒有看到,就把它刪掉,然後用同樣的方法試試
~/.bash_profile - 如果前兩個都不行,也可以試試
~/.profile
(網路上有很多詳細的流程圖在解釋 bash 會如何決定要用哪個設定檔,但我覺得與其把它們背起來,直接動手測試才是最快、最保險的方法)
步驟 3:搞清楚要加入哪個目錄
假設你想要安裝並執行一個叫做 http-server 的程式,結果卻像這樣無法執行:
$ npm install -g http-server
$ http-server
bash: http-server: command not found要怎麼找出 http-server 到底在哪個目錄裡?老實說,這通常沒那麼簡單——答案常常是「要看 npm 是怎麼設定的」之類的。這裡有幾個可以試的方法:
- 通常在初次設定新的安裝工具(像是
cargo、npm、homebrew等)時,它會印出如何更新 PATH 的說明。所以如果你當時有留意,就能直接拿到指示。 - 有時候安裝程式會自動幫你更新 shell 設定檔,直接幫你把
PATH設定好 - 有時候直接 Google「where does npm install things?」就能找到答案
- 有些工具本身就有子指令可以告訴你它們被設定安裝到哪裡,例如:
- Node/npm:
npm config get prefix(然後再加上/bin/) - Go:
go env GOPATH(然後再加上/bin/) - asdf:
asdf info | grep ASDF_DIR(然後再加上/bin/和/shims/)
- Node/npm:
步驟 3.1:再次確認是正確的目錄
一旦找到你認為可能是正確的目錄,一定要確認它真的正確!舉例來說,我發現我的電腦上 http-server 位在 ~/.npm-global/bin。我可以像這樣直接執行該目錄下的 http-server 來確認:
$ ~/.npm-global/bin/http-server
Starting up http-server, serving ./public成功了!既然你已經知道要把哪個目錄加入 PATH,就來進行下一步吧!
步驟 4:編輯你的 shell 設定檔
現在我們已經有了需要的兩個關鍵資訊:
- 你想加入 PATH 的是哪個目錄(例如
~/.npm-global/bin/) - 你的 shell 設定檔在哪裡(例如
~/.bashrc、~/.zshrc或~/.config/fish/config.fish)
接下來要加入什麼,取決於你用的是哪一種 shell:
bash 設定方式:
打開你的 shell 設定檔,並加入像這樣的一行:
export PATH=$PATH:~/.npm-global/bin/(記得把 ~/.npm-global/bin 換成你實際要加入的目錄)
zsh 設定方式:
你可以用跟 bash 一樣的方法,不過 zsh 也有稍微花俏一點的語法,如果你喜歡的話可以用:
path=(
$path
~/.npm-global/bin
)fish 設定方式:
在 fish 裡,語法不太一樣:
set PATH $PATH ~/.npm-global/bin(在 fish 裡你也可以使用 fish_add_path,相關說明請見下方)
步驟 5:重新啟動你的 shell
現在是非常重要的一步:如果你沒有重新啟動 shell,更新設定檔是不會生效的!
有兩種做法:
- 開啟一個新的終端機(或新的終端機分頁),最好把舊的關掉,才不會搞混
- 執行
bash來啟動一個新的 shell(如果你用 zsh 就執行zsh,用 fish 就執行fish)
我發現這兩種方法通常都沒問題。
這樣應該就完成了!試著執行你原本想跑的程式,應該就能正常運作了。
如果還是不行,以下是你可能會遇到的幾個問題:
問題 1:執行到錯誤的程式
如果執行到錯誤版本的程式,你可能需要把目錄加到 PATH 的最前面,而不是最後面。
舉例來說,我的系統上安裝了兩個版本的 python3,用 which -a 就可以看到:
$ which -a python3
/usr/bin/python3
/opt/homebrew/bin/python3你的 shell 會使用列在最前面的那一個。
如果你想用 Homebrew 的版本,就得把那個目錄(/opt/homebrew/bin)加到 PATH 的最前面,也就是在設定檔中加入這一行(是 /opt/homebrew/bin/:$PATH,而不是常見的 $PATH:/opt/homebrew/bin/)
export PATH=/opt/homebrew/bin/:$PATH或是在 fish 中:
set PATH ~/.cargo/bin $PATH問題 2:程式不是從你的 shell 執行的
以上這些步驟只有在你從 shell 裡執行程式時才有效。如果你是從 IDE、圖形介面、cron 工作,或其他方式執行程式,就得用不同的方法把目錄加入 PATH,實際做法會依情況而定。
在 cron 工作中
有幾個選項:
- 使用你要執行的程式的完整路徑,例如
/home/bork/bin/my-program - 把你想要的完整 PATH 放在 crontab 的第一行(像是 PATH=/bin:/usr/bin:/usr/local/bin:…)。你可以在 shell 中執行
echo "PATH=$PATH"來取得目前使用的完整 PATH。
老實說,我已經很久沒遇到在 IDE/圖形介面中處理這類問題的情況,所以不太確定該怎麼處理,如果有人能指點正確方向,我會再把說明補上來。
問題 3:重複的 PATH 項目讓除錯更困難
如果你編輯了 path 然後用執行 bash(或 zsh、fish)的方式來啟動新的 shell,常常會產生重複的 PATH 項目,因為 shell 每次啟動時都會不斷把新的東西加到 PATH 裡。
就我個人經驗,我不覺得這種重複會真的造成什麼嚴重的問題,但如果你想搞清楚 PATH 裡到底有什麼,重複的項目會讓除錯變得比較困難。
你可以透過以下幾種方法來處理:
- 如果你在除錯
PATH,就在全新的終端機裡進行,這樣會得到「乾淨的」狀態,應該可以避免重複。 - 在 shell 設定檔的最後把
PATH去除重複(例如在 zsh 裡據說可以用typeset -U path做到) - 在加入目錄時,先檢查該目錄是否已經在
PATH裡(例如在 fish 裡我相信可以用fish_add_path --path /some/directory做到)
如何幫 PATH 去除重複取決於你用的 shell,而且不一定有內建的方法,所以你得自己去查在你的 shell 中該怎麼做。
問題 4:更新 PATH 後遺失歷史紀錄
這是在 bash 或 zsh 中很容易遇到的情況:
- 執行一個指令(結果失敗)
- 更新你的
PATH - 執行
bash來重新載入設定 - 按幾下方向鍵的上鍵,想重新執行剛剛失敗的指令(或開啟一個新的終端機)
- 結果失敗的指令不在歷史紀錄裡!為什麼會這樣?
這是因為在 bash 中,預設要等到你離開 shell 後,歷史紀錄才會被儲存。
有幾種修正方法:
- 與其執行
bash來重新載入設定,不如執行source ~/.bashrc(在 zsh 則是source ~/.zshrc)。這樣會在目前的工作階段內重新載入設定。 - 把 shell 設定成持續儲存歷史紀錄,而不是只有在離開時才儲存。(具體做法取決於你用 bash 還是 zsh,zsh 的歷史紀錄選項有點複雜,我也不太確定最好的方法是什麼)
關於 source 的補充說明
當你第一次安裝 cargo(Rust 的安裝工具)時,它會給你這樣的 PATH 設定說明,裡面完全沒提到具體的目錄。
This is usually done by running one of the following (note the leading DOT):
. "$HOME/.cargo/env" # For sh/bash/zsh/ash/dash/pdksh
source "$HOME/.cargo/env.fish" # For fish它的想法是,你把那一行加到 shell 設定檔裡,它們的腳本就會自動幫你設定好 PATH(以及可能的其他東西)。
這種做法很常見(例如 Homebrew 就建議你執行 brew shellenv),而你有兩種處理方式:
- 照著工具建議的做(例如把
. "$HOME/.cargo/env"加到 shell 設定檔裡) - 搞清楚它們叫你執行的腳本實際上會把哪些目錄加入 PATH,然後手動加入。我的做法會是這樣:
- 在我的 shell 中執行
. "$HOME/.cargo/env"(如果用 fish 就執行 fish 的版本) - 執行
echo "$PATH" | tr ':' '\n' | grep cargo來找出它加了哪些目錄 - 看到它顯示
/Users/bork/.cargo/bin,然後縮寫成~/.cargo/bin - 用這篇文章裡的方法把
~/.cargo/bin這個目錄加入 PATH
- 在我的 shell 中執行
我不覺得照著工具建議的做有什麼不對(那搞不好就是「最好的方法」!),但我個人通常會用第二種做法,因為我比較喜歡清楚知道自己到底改了什麼設定。
關於 fish_add_path 的補充說明
fish 有一個很好用的函式叫做 fish_add_path,你可以像這樣用它來把目錄加入 PATH:
fish_add_path /some/directory這很酷(指令這麼簡單!)但我已經不再用它了,原因有幾個:
- 有時候
fish_add_path會用「universal variable」幫你更新之後所有工作階段的PATH,有時候卻只會更新目前工作階段的PATH,我很難分辨它到底會做哪一種。理論上文件有說明,但我看不懂。 - 如果你在幾週或幾個月後,因為發現弄錯了而想把某個目錄從
PATH中移除,會有點麻煩(不過這個 GitHub issue 的留言裡有說明做法)。
就是這樣
希望這能幫到一些人。如果你還知道其他在把目錄加入 PATH 時容易踩到的大坑,或對這篇文章有任何問題,歡迎在 Mastodon 或 Bluesky 上告訴我!
隨機一篇部落格
留言
登入後參與討論