Более удобный способ редактировать длинную переменную $ PATH?


35

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

Я знаю, что такой синтаксис недействителен. Мне было интересно, если есть что-то так просто. Есть?


Традиционный учебник , чтобы установить путь через PATH=foo:$PATHкажется неправильным , потому что удержать рост каждый раз , source ~/.bashrcи даже exec bashне может помочь , так как $PATHэто export.
— 皞 皞

Ответы:


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)добавив текущий каталог в путь.


Спасибо. Я проверил ваш код, и он работает. Удивительно, но я также нашел использование del_path (A "." В некоторых ситуациях закрадывается в мой PATH, черт знает откуда, и я это сделал del_path .).
— Никколо М.

Здравствуй. Можно ли включить (включить) эти pathfuncs из скрипта bashrc или я должен скопировать / вставить их туда?
— Криштиану

@Cristiano Либо будет работать. Это действительно зависит от вас.
— Морская звезда

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)).


1
Очень хорошо. Можете ли вы принять ответ, чтобы другие не пришли сюда, чтобы предложить решение, когда вы уже нашли его? Спасибо
— Basic

Дублирующие пути на самом деле не проблема. Маловероятно, что у вас будет достаточно каталогов, чтобы PATHвызвать проблемы с производительностью (особенно если оболочка кэширует успешные поиски).
— Чепнер

5

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

Спасибо. Но я выберу решение @ Starfish, потому что его не появляется grep.
— Никколо М.

2
@NiccoloM. нет проблем, примите то, что вы предпочитаете. Будьте осторожны с подходом starfish, хотя он выполнит произвольный код, evalтак что вы можете нанести серьезный ущерб, если запустите его с неверным аргументом.
— Terdon

Обратите внимание , что быстрее функция существует в RedHat , чтобы сделать это без внешней команды grep, см bugzilla.redhat.com/show_bug.cgi?id=544652#c7
— 林果皞

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 каталогами, которые могут
## не подходит для этого сервера, постарайтесь понять, что мы добавляем
##
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 ". Это гарантирует, что я получу чистую копию в нужном мне порядке.


1
предложение альтернативы: d="/usr/share/man" ; [ -d "$d" ] && MANPATH="$MANPATH:${d}"будет проще и проще добавить новый каталог (просто скопируйте строку и отредактируйте первую часть "d = ...."). Тем не менее, для PATH, я думаю, вы получите слишком много директорий в PATH, что не всегда хорошо (что если какая-то команда «foo» существует в одном из менее известных путей, и вы делаете что-то совершенно другое) то, что ожидают обычные пользователи?)
— Оливье Дюлак

ОП попросил более краткий способ добавить пути. Это гораздо более многословно и более подвержено ошибкам, чем то, что они уже пытались избежать.
— underscore_d

-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/.


3
Что это за функции? Как ОП их использует? Предположительно они описаны в неработающей ссылке в вашем ответе, именно поэтому мы всегда хотим, чтобы ответы были самодостаточными. Пожалуйста, отредактируйте и включите фактические функции в ваш ответ.
— тердон

@terdon: ссылка работает для меня, я помещаю файл .shar в pastebin, я не буду публиковать здесь 1K строк.
— Вальтинатор

Ой, у меня тоже работает. Это не когда я оставил комментарий. В любом случае, суть моего комментария заключалась в том, что мы стараемся избегать ссылок на внешние ресурсы в ответах. Мы хотим, чтобы информация была здесь, где она может быть обновлена, отредактирована и защищена от гниения ссылок.
— Terdon
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.