
Я хотел бы изменить $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
Обсуждение
Я думаю, что у garyjohn основной подход правильный, но он ищет всех потомков, а не всех предков.
Переменная $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