
我想$PATH
根據目前的工作目錄更改環境變數。
假設我已經進入/foo/bar/baz
並且我有目錄/foo/node_modules/.bin
和/foo/bar/baz/node_modules/.bin
.我想將所有可能的./node_modules/.bin
遞歸添加到$PATH
.
但是當我cd
進入不同的目錄(例如/foo/bar
)時,我希望$PATH
恢復原始的、乾淨的目錄,然後再次開始遞歸查找./node_modules/.bin
。
(我想從 npm 的問題追蹤器中解決我自己的問題:我們是否也可以將本地安裝的軟體包新增到 PATH 中?)
注意:我使用的是 Mac,但對通用解決方案感興趣。
答案1
介紹
如果我理解正確的話,您想要添加或其任何祖先"$X/node_modules/.bin"
所在$X
的任何目錄。$PWD
本文末尾的腳本應該給出您想要的行為。您需要在每個需要的會話中獲取它。如果您將文件命名為augment_path.sh
,那麼將此行添加到您的文件中.bashrc
就足夠了:
source augment_path.sh
討論
我認為加里約翰的基本方法是正確的,但他正在搜索所有後代而不是所有祖先。
此$PROMPT_COMMAND
變數可讓您指定每次顯示提示時要執行的命令。我添加了一個變數以允許恢復$PROMPT_COMMAND_OLD
原始內容$PROMPT_COMMAND
這可能沒有必要,但為了良好的形式,我添加了一個$LAST_WD
變數並進行測試,以避免在目錄未更改時重新計算路徑。LAST_WD
如果您願意,可以刪除包含的所有三行。
該augment_path
函數從向上掃描$PWD
,在每個祖先中尋找目標目錄並將找到的任何目錄新增至路徑。
它們按順序放置在路徑中,因此如果有任何衝突,將優先考慮最深的目錄。我認為這是期望的行為。如果沒有,請更改
PATH_ADDITION="$PATH_ADDITION:$resolved_target"
到
PATH_ADDITION="$resolved_target:$PATH_ADDITION"
但是,這些目錄都將優先於路徑的其餘部分。如果您希望路徑的其餘部分優先,請變更:
PATH="$PATH_ADDITION:$RAW_PATH"
到
PATH="$RAW_PATH:$PATH_ADDITION"
腳本
RAW_PATH="$PATH"
LAST_WD=`pwd`
augment_path() {
target="node_modules/.bin"
if [ "$PWD" = "$LAST_WD" ]; then return 0; fi;
PATH_ADDITION=""
scandir="$PWD"
until [ "$scandir" = "" ]; do
resolved_target="$scandir"/"$target"
if [ -d "$resolved_target" ]; then
PATH_ADDITION="$PATH_ADDITION:$resolved_target"
fi
scandir="${scandir%/*}"
done
PATH="$PATH_ADDITION:$RAW_PATH"
LAST_WD=`pwd`
}
PROMPT_COMMAND_OLD="${PROMPT_COMMAND%; augment_path}"
PROMPT_COMMAND="$PROMPT_COMMAND_OLD; augment_path"
答案2
你可以使用 bashPROMPT_COMMAND
:
PROMPT_COMMAND='[ -z "$X" ] && X=$PATH; PATH=$X:$(pwd)/node_modules/.bin'
每次出現提示時都會執行該指令。因此,每次命令完成時,PATH
變數都會更改。最後新增了一個附加目錄。
如果目前工作目錄中沒有目錄./node_modules/.bin
,則無論如何都會附加路徑。但是,這不是問題。不會搜尋它(因為它不存在)。
看示範:
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
$ PROMPT_COMMAND='[ -z "$X" ] && X=$PATH; PATH=$X:$(pwd)/node_modules/.bin'
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/node_modules/.bin
$ cd test
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/test/node_modules/.bin
$ cd /etc/
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/etc/node_modules/.bin
答案3
我認為將以下內容放入您的遺囑中~/.bashrc
可以滿足您的要求。
如果 bash 環境變數PROMPT_COMMAND
設定為某個指令,則指令會在 bash 顯示主提示字元之前執行。
在下面的程式碼中,PROMPT_COMMAND
被設定為函數的名稱doit
。此函數會檢查目前工作目錄是否已更改,如果是,請先設定PATH
為其原始值,然後檢查是否存在名為 的子目錄node_modules/.bin
。如果該子目錄存在,則函數會將其名稱及其下面的所有子目錄附加到PATH
.
orig_path="$PATH"
prev_pwd=""
doit() {
if [ "$PWD" != "$prev_pwd" ]; then
PATH="$orig_path"
if [ -d "node_modules/.bin" ]; then
PATH="$PATH$(find $PWD/node_modules/.bin -type d -printf ':%p')"
# For POSIX compatibility (macOS or other), use:
# PATH="$PATH$(find $PWD/node_modules/.bin -type d -exec echo -n :{} \;)"
fi
prev_pwd="$PWD"
fi
}
PROMPT_COMMAND=doit