34

Я хочу добавить в ~/.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 ответов6

25

Я использую набор вспомогательных функций для добавления или добавления пути к переменной. Функции входят в дистрибутивный пакет для 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) чтобы добавить текущий каталог в путь.

11

Хорошо, я разобрался со следующим решением, которое я считаю элегантным (с точки зрения синтаксиса оболочки). Он использует синтаксис массива 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)).

4

Я использую функцию ниже в моем ~/.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 after) $PATH .

Файл инициализации вашей оболочки будет содержать что-то вроде:

pathmunge /some/dir
pathmunge /another/dir
pathmunge '/another/dir with spaces in it'
pathmunge /yet/another
pathmunge /and/another
pathmunge /end
4

Я хочу добавить в ~/.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
1

Я использую это в моем .bashrc (а также в моем .zshrc, так как я обычно использую zsh там, где он доступен вместо bash). Конечно, это требует от меня добавления каталогов вручную, но преимущество заключается в том, что при обновлении я могу продолжать копировать его на новые серверы и не беспокоиться о PATH на новом сервере, который создается с каталогами, которых там нет.

##
## PATH
##
## Instead of just clobbering our PATH with directories that may
## not be appropriate for this server, try to be intelligent about what we add
##
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
[ -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
##
## Instead of just clobbering our MANPATH with directories that may
## not be appropriate for this server, try to be intelligent about what we add
##
MANPATH=/usr/local/man
[ -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:/ новый / реж». Это гарантирует, что я получу чистую копию в нужном мне порядке.

-1

Есть простой способ! Прочитайте функции оболочки и переменные пути в 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/.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .