Более удобный способ редактировать длинную переменную $PATH?
Я хочу добавить в ~/.bashrc несколько каталогов к моему $PATH.
Мой $ PATH довольно длинный, поэтому трудно понять, какие каталоги он содержит и в каком порядке.
Я знаю, что могу изменить мой ~/.bashrc так:
PATH=$PATH:/some/dir
PATH=$PATH:/another/dir:/yet/another
PATH=$PATH:/and/another
...
было бы легче читать. Но мне было интересно, если в последние годы Bash приобрел некоторый синтаксис, который облегчает определение длинного PATH. Например, я фантазирую о синтаксисе, похожем на:
PATH=:((
/some/dir
/another/dir
/yet/another
/and/another
...
))
Я знаю, что такой синтаксис недействителен. Мне было интересно, если есть что-то так просто. Есть?
6 ответов
Я использую набор вспомогательных функций для добавления или добавления пути к переменной. Функции входят в дистрибутивный пакет для Bash в файле contrib под названием "pathfuncs".
- add_path добавит запись в конец переменной PATH
- pre_path добавит запись в начало переменной PATH
- del_path удалит запись из переменной PATH, где бы она ни находилась
Если вы укажете переменную в качестве второго аргумента, она будет использовать ее вместо PATH.
Для удобства вот они:
# is $1 missing from $2 (or PATH) ?
no_path() {
eval "case :\$${2-PATH}: in *:$1:*) return 1;; *) return 0;; esac"
}
# if $1 exists and is not in path, append it
add_path () {
[ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="\$${2:-PATH}:$1"
}
# if $1 exists and is not in path, prepend it
pre_path () {
[ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="$1:\$${2:-PATH}"
}
# if $1 is in path, remove it
del_path () {
no_path $* || eval ${2:-PATH}=`eval echo :'$'${2:-PATH}: |
sed -e "s;:$1:;:;g" -e "s;^:;;" -e "s;:\$;;"`
}
Если вы добавите их в свой загрузочный файл bash, вы можете добавить их в PATH, например:
pre_path $HOME/bin
add_path /sbin
add_path /usr/sbin
Или укажите другую переменную:
pre_path $HOME/man MANPATH
pre_path $HOME/share/man MANPATH
add_path /usr/local/man MANPATH
add_path /usr/share/man MANPATH
Я использую этот метод в моих файлах rc, ставя сначала pre_paths, а затем add_paths. Это делает все мои изменения пути легко понятными с первого взгляда. Еще одним преимуществом является то, что строки достаточно короткие, чтобы при необходимости я мог добавить заключительный комментарий к строке.
А так как это функции, вы можете использовать их в интерактивном режиме из командной строки, например, говоря add_path $(pwd)
добавить текущий каталог в путь.
Хорошо, я разобрался со следующим решением, которое я считаю элегантным (с точки зрения синтаксиса оболочки). Он использует синтаксис массива Bash, а также удобный способ объединения элементов:
paths=(
/some/dir
/another/dir
'/another/dir with spaces in it'
/yet/another
/and/another
/end
)
paths_joined=$( IFS=: ; echo "${paths[*]}" )
PATH=$paths_joined:$PATH
ALERT!
Оказывается, у этого решения есть проблема: в отличие от решений @terdon и @Starfish, он сначала не проверяет, есть ли пути в PATH. Итак, поскольку я хочу поместить этот код в ~/.bashrc (а не в ~/.profile), повторяющиеся пути будут ползти в PATH. Так что не используйте это решение (если только вы не поместите его в ~/.profile (или, лучше, ~/.bash_profile, так как он имеет специальный синтаксис Bash)).
Я использую функцию ниже в моем ~/.bashrc
, Это то, что я получил от сисадмина в моей старой лаборатории, но я не думаю, что он их написал. Просто добавьте эти строки в свой ~/.profile
или же ~/.bashrc
:
pathmunge () {
if ! echo $PATH | /bin/grep -Eq "(^|:)$1($|:)" ; then
if [ "$2" = "after" ] ; then
PATH=$PATH:$1
else
PATH=$1:$PATH
fi
fi
}
Это имеет различные преимущества:
- Добавление новых каталогов в
$PATH
тривиально:pathmunge /foo/bar
; - Избегает дублирования записей;
- Вы можете выбрать, добавлять ли новую запись в начало (
pathmunge /foo/bar
или конец (pathmunge /foo/bar
после) из$PATH
,
Файл инициализации вашей оболочки будет содержать что-то вроде:
pathmunge /some/dir
pathmunge /another/dir
pathmunge '/another/dir with spaces in it'
pathmunge /yet/another
pathmunge /and/another
pathmunge /end
Я хочу добавить в ~/.bashrc несколько каталогов к моему $PATH.
Я использую следующее в Cygwin. Должно работать в других версиях bash. Вы можете удалить unset PATH
строить на своем нынешнем PATH
(если вы сделаете это, вам, возможно, придется выяснить, как добавить :
разделители правильно).
Замечания:
- У меня когда-то была эта функциональность в
bash
функция, но потеряла его после сбоя диска.
В моем .bash_profile
:
# Build up the path using the directories in ~/.path_elements
unset PATH
while read line; do
PATH="${PATH}$line";
done < ~/.path_elements
...
# Add current directory to path
export PATH=".:${PATH}"
В ~/.path_elements
:
/home/DavidPostill/bin:
/usr/local/bin:
/usr/bin:
/c/Windows/system32:
/c/Windows
Я использую это в моем.bashrc (а также в моем.zshrc, так как я обычно использую zsh там, где он доступен вместо bash) Конечно, это требует от меня добавления каталогов вручную, но преимущество заключается в том, что при обновлении я могу продолжать копировать его на новые серверы и не беспокоиться о PATH на новом сервере, который создается с каталогами, которых там нет.
## ## ДОРОЖКА ## ## Вместо того, чтобы просто забивать наш PATH каталогами, которые могут ## не подходит для этого сервера, постарайтесь понять, что мы добавляем ## PATH=/ USR / местные / SBIN: / USR / местные / бен: / USR / SBIN: / USR / бен: / SBIN: / бен [ -d /cs/sbin ] && PATH=/cs/sbin:$PATH [ -d /cs/bin ] && PATH=/cs/bin:$PATH [ -d /usr/ucb ] && PATH=$PATH:/usr/ucb [ -d /usr/ccs/bin ] && PATH=$PATH:/usr/ccs/bin [ -d /usr/local/ssl/bin ] && PATH=$PATH:/usr/local/ssl/bin [ -d /usr/krb5/bin ] && PATH=$PATH:/usr/krb5/bin [ -d /usr/krb5/sbin ] && PATH=$PATH:/usr/krb5/sbin [ -d /usr/kerberos/sbin ] && PATH=$PATH:/usr/kerberos/sbin [ -d /usr/kerberos/bin ] && PATH=$PATH:/usr/kerberos/bin [ -d /cs/local/jdk1.5.0/bin ] && PATH=$PATH:/cs/local/jdk1.5.0/bin [ -d /usr/java/jre1.5.0_02/bin ] && PATH=$PATH:/usr/java/jre1.5.0_02/man [ -d /usr/java1.2/bin ] && PATH=$PATH:/usr/java1.2/bin [ -d /cs/local/perl5.8.0/bin ] && PATH=$PATH:/cs/local/perl5.8.0/bin [ -d /usr/perl5/bin ] && PATH=$PATH:/usr/perl5/bin [ -d /usr/X11R6/bin ] && PATH=$PATH:/usr/X11R6/bin [ -d /etc/X11 ] && PATH=$PATH:/etc/X11 [ -d /opt/sfw/bin ] && PATH=$PATH:/opt/sfw/bin [ -d /usr/local/apache/bin ] && PATH=$PATH:/usr/local/apache/bin [ -d /usr/apache/bin ] && PATH=$PATH:/usr/apache/bin [ -d /cs/admin/bin ] && PATH=$PATH:/cs/admin/bin [ -d /usr/openwin/bin ] && PATH=$PATH:/usr/openwin/bin [ -d /usr/xpg4/bin ] && PATH=$PATH:/usr/xpg4/bin [ -d /usr/dt/bin ] && PATH=$PATH:/usr/dt/bin
Я делаю то же самое для моего MANPATH:
## ## MANPATH ## ## Вместо того, чтобы просто загромождать наш МАНПАТ каталогами, которые могут ## не подходит для этого сервера, постарайтесь понять, что мы добавляем ## MANPATH=/ USR / местные / человек [ -d /usr/share/man ] && MANPATH=$MANPATH:/usr/share/man [ -d /usr/local/share/man ] && MANPATH=$MANPATH:/usr/local/share/man [ -d /usr/man ] && MANPATH=$MANPATH:/usr/man [ -d /cs/man ] && MANPATH=$MANPATH:/cs/man [ -d /usr/krb5/man ] && MANPATH=$MANPATH:/usr/krb5/man [ -d /usr/kerberos/man ] && MANPATH=$MANPATH:/usr/kerberos/man [ -d /usr/local/ssl/man ] && MANPATH=$MANPATH:/usr/local/ssl/man [ -d /cs/local/jdk1.5.0/man ] && MANPATH=$MANPATH:/cs/local/jdk1.5.0/man [ -d /usr/java/jre1.5.0_02/man ] && MANPATH=$MANPATH:/usr/java/jre1.5.0_02/man [ -d /usr/java1.2/man ] && MANPATH=$MANPATH:/usr/java1.2/man [ -d /usr/X11R6/man ] && MANPATH=$MANPATH:/usr/X11R6/man [ -d /usr/local/apache/man ] && MANPATH=$MANPATH:/usr/local/apache/man [ -d /usr/local/mysql/man ] && MANPATH=$MANPATH:/usr/local/mysql/man [ -d /cs/local/perl5.8.0/man ] && MANPATH=$MANPATH:/cs/local/perl5.8.0/man [ -d /usr/perl5/man ] && MANPATH=$MANPATH:/usr/perl5/man [ -d /usr/local/perl/man ] && MANPATH=$MANPATH:/usr/local/perl/man [ -d /usr/local/perl5.8.0/man ] && MANPATH=$MANPATH:/usr/local/perl5.8.0/man [ -d /usr/openwin/man ] && MANPATH=$MANPATH:/usr/openwin/man
В дополнение к наличию одного файла, который я могу копировать в системы в разнородных средах, не опасаясь добавления несуществующих каталогов в PATH, этот подход также имеет то преимущество, что позволяет мне указать порядок, в котором я хочу, чтобы каталоги появлялись в PATH. Так как первая строка каждого определения полностью переопределяет переменную PATH, я могу обновить мой.bashrc и получить его после редактирования, чтобы обновить оболочку, не добавляя дублирующиеся записи (с которыми я сталкивался давным-давно, когда просто начинал с "$PATH=$PATH:/new/dir". Это гарантирует, что я получу чистую копию в нужном мне порядке.
Есть простой способ! Прочитайте функции оболочки и переменные пути в Linux Journal, 01 марта 2000 г. Стивен Коллайер
Функции позволяют мне использовать новый тип данных в моей среде bash - список, разделенный двоеточиями. В дополнение к PATH я использую их для настройки моих LOCATE_PATH, MANPATH и других, а также в качестве общего типа данных в программировании bash. Вот как я настроил свой PATH (используя функции):
# Add my bin directory to $PATH at the beginning, so it overrides
addpath -f -p PATH $HOME/bin
# For Raspberry Pi development (add at end)
addpath -b -p PATH ${HOME}/rpi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin
# remove nonexistent directories from PATH
delpath -n -p PATH
# ensure PATH contains unique entries
uniqpath -p PATH
Поскольку ссылка на журнал Linux называется "неработающей", я поместил функции пути Bash в файл.shar по адресу http://pastebin.ubuntu.com/13299528/