Zsh

在 zsh 中更改 PATH 變數

  • April 11, 2022

我想在 zsh 中更改我的 PATH 變數。

問題:我不明白.zshrc我必須在文件的哪個位置進行修改。

通常,我會尋找對 PATH 變數的賦值,並從頭開始設置我希望它們的值(保持所有系統二進製文件目錄不變)。

我的 .zshrc 文件中的第一行如下:

# If you come from bash you might have to change your $PATH.
# export PATH=$HOME/bin:/usr/local/bin:$PATH

# Path to your oh-my-zsh installation.
export ZSH="/Users/Sam/oh-my-zsh"

export PATH=$PATH:/Applications/Postgres.app/Contents/Versions/13/bin

等等

我的實際 PATH 變數是:

/Library/Frameworks/Python.framework/Versions/3.9/bin:/Library/Frameworks/Python.framework/Versions/3.8/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Postgres.app/Contents/Versions/13/bin

我想刪除python3.8所在的目錄,是多餘的。

我的問題:

  1. 我是否必須更改 .zshrc 文件中的第 2 行或第 7 行?
  2. 第 2 行被註釋掉了……它是否在終端開始時仍然執行?
  3. 我試圖註釋掉第 7 行。但是 postgres 目錄仍然保留在我不明白的 PATH 變數中。

從評論重新發佈到答案,但有一些額外的註釋。

首先,在網上搜尋有關使用 Unx shell(命令行)和終端會話的介紹性指南。它們中的大多數都提供了有關最常見環境變數的大量資訊,例如 PATH。(但是,有些人可能沒有詳細說明PATH 變數設置/修改/等的許多地方。)*

其次,了解環境變數是每個實例的,這意味著每個程序在啟動時都會獲得它自己的變數副本(來自父程序),並且沒有“全域環境”之類的東西。如果您打開兩個終端實例,您可以看到這一點,在一個終端中鍵入export PATH="",清除 PATH 變數,然後在另一個終端中鍵入echo $PATH。您將看到第二個中的 PATH 變數不受第一個終端視窗中的清除的影響。

第三,盡量避免在一個問題中問多個問題,除非這些問題都非常密切相關。

我將在所問的問題之間來回跳躍(因為它們非常密切相關)。另外,我經常使用bash語法/命令。不同的 shell 可能使用其他形式(例如setvarin tcsh)。

創建使用者主目錄 ($HOME) 時(通常在創建使用者記錄時)從骨架(模板)文件複製預設 .zshrc文件 - 請記住,如果您的系統管理員修改了骨架文件,新版本不會複製到您已經存在的主目錄中!)。這些骨架文件通常位於類似的位置/etc/skel,其他位置可能是為特定的 shell 定義的,或者由您的系統管理員定義。

這些預設/骨架文件通常包含常見用法範例,有時會被註釋掉(以“#”為前綴),因此當您在使用者主目錄中編輯它們時,您可以根據自己的喜好或需要取消註釋或編輯它們。

請記住,並非所有這些文件都會自動載入。它們僅在您“登錄”時載入——有些可能僅在您通過 GUI 登錄時載入,而另一些僅在您登錄文本模式控制台時載入。通常,不同的 shell 使用.<shell>rc諸如 、.bashrc.zshrc– 它們通常簡稱為“rc 文件” – 來定義登錄/啟動該 shell 時的預設配置。請特別注意,這意味著如果您從 cron 作業或 GUI 啟動器等不載入 shell 及其 rc 文件的東西執行程序,則 rc 文件中設置的任何命令或變數都不可用。

還要記住,每次編輯 rc 文件時,shell不會自動*重新載入它們。*要在編輯後“重新載入”它們,您需要source .zshrc(或source .bashrc等),或關閉/退出 shell/終端並重新登錄。某些 shell 可以強制會話重新載入,您必須閱讀 shell 的手冊頁以了解怎麼做。

使用該source .zshrc方法時,您還需要記住保留以前的設置和值。這意味著,除非您的 rc 文件顯式清除 PATH 變數,否則它將繼續包含先前的值並添加rc 文件添加的任何內容——即使先前載入的 rc 文件已經添加了它。例如,將以下程式碼放入名為“growvar.sh”的文件中:

export GROWVAR="$GROWVAR:Grow!"
echo "GROWVAR now contains \"$GROWVAR\""

並保存它。然後注意以下命令和結果:

$ source growvar.sh
GROWVAR now contains ":Grow!"
$ source growvar.sh
GROWVAR now contains ":Grow!:Grow!"
$ source growvar.sh
GROWVAR now contains ":Grow!:Grow!:Grow!"

(另請注意,您需要這樣做source:將文件設置為執行檔 ( chmod +x ...) 不會像您預期的那樣,因為它會在子 shell 中“執行”而不影響父 shell 程序環境。)

這通常對 PATH 是無害的,因為大多數 shell 都會跳過檢查它已經檢查過的 $PATH 的每個部分。它們還忽略“空”路徑,例如“::”(實際上是由“:”分隔的*三個空路徑)。*這就是為什麼`export PATH=" $ PATH:/new/path/here" will still work even if $ PATH 之前沒有設置。但是,如果您向 PATH 變數添加許多長路徑,它可能會因多個冗餘路徑而變得非常大。(甚至可能會耗盡可用的環境空間記憶體。)

我確定我忘記了一些東西……但這是它們如何联系在一起的:

問題 #1:更改第 7 行 - 或者.. 只需將其註釋掉並添加“更正”版本。這樣以後,你可以立即看到你改變了它,改變之前是什麼,改變之後是什麼。對骨架文件中註釋掉的“範例”程式碼執行相同的操作。不要取消註釋:複製程式碼,根據自己的喜好進行調整,然後取消註釋副本。

問題 #2:如上所示,“#”使該行成為註釋行,shell 會簡單地忽略它。

問題#3:很可能,您希望更改 rc 文件會自動重新載入它(我在上面解釋過它不會這樣做),或者如果您確實重新載入(通過source命令),您希望 PATH清除它的目前值(我在上面也解釋過不是這種情況)。您需要完全重新啟動/重新載入 shell 以獲取更改。

問題(來自評論)#1:“它在哪裡得到 $ PATH from?" It depends. Initially, PATH does not even exist. If you try to reference it, as in $ PATH,它只是返回一個空字元串(“”)。一旦您登錄到您的 shell,shell 將自動source生成一些系統預設文件,通常位於/etc/default(以及其他地方,您的 shell 的手冊頁將為您提供 shell 的詳細資訊),這些文件設置 PATH 變數以供進一步使用。這就是為什麼大多數範例 PATH 設置使用export PATH="$PATH:/new/path/here",因此它們可以保留任何以前設置的路徑(如果 PATH 以前不存在,則根本不保留)。

問題(來自評論)#2:關於關於“ $ HOME/bin": Many experienced Un*x users have their own $ HOME/bin 目錄以提供自定義命令和特定於其登錄的覆蓋。因此,範例配置行通過將目錄添加到 PATH 來展示這一點。PATH 變數中任何不存在的目錄都會被忽略並跳過而不會出錯。

編輯添加:哦,還有……在極端情況下 $ HOME not being defined, it simply gets replaced by an empty string the same way PATH does. So, " $ HOME/bin" 計算結果為 “/bin”。

另一個“編輯添加”的東西可以進一步幫助:如果您的目標是簡單地清理 PATH,您可以編寫一個簡單的實用程序來執行此操作 - 但您必須記住該實用程序只能修改它自己的 PATH 副本. 您可以通過使實用程序輸出(在標準輸出上)清理路徑來解決此問題,父程序/shell 可以讀取該路徑以設置新路徑。例如:

...
export PATH=`/bin/mypathutil --cleanup`
...

我實際上有一個 TCL 腳本,/bin/cleanpath它輸出一個路徑,每個目錄只給出一次。所以像“/bin:/bin:/usr/bin:/bin:/usr/bin:/usr/games:/bin:/bin”這樣的東西會簡單地輸出“/bin:/usr/bin:usr/games” . (從技術上講,我的腳本做的稍微多一些,例如確保我的特殊自定義目錄,/usr/local/overrides始終在 PATH 中排在第一位,因此我總是可以將自定義命令覆蓋放在那裡。這樣,我還可以通過在 /usr/ 中創建符號連結來臨時禁用一些命令local/override 只是指向/bin/true. (這可能不適用於 shell 內置程序,或者使用執行檔的完整路徑名的程序……)

引用自:https://unix.stackexchange.com/questions/662787