Кто-нибудь написал функцию bash для добавления каталога в $ PATH, только если его там еще нет?
Я обычно добавляю в PATH что-то вроде:
export PATH=/usr/local/mysql/bin:$PATH
Если я создаю свой PATH в .bash_profile, он не будет прочитан, если только сеанс, в котором я нахожусь, не является сеансом входа в систему - что не всегда верно. Если я создаю свой PATH в .bashrc, то он запускается с каждой подоболочкой. Поэтому, если я запускаю окно терминала, затем запускаю screen и затем запускаю сценарий оболочки, я получаю:
$ echo $PATH
/usr/local/mysql/bin:/usr/local/mysql/bin:/usr/local/mysql/bin:....
Я собираюсь попробовать создать функцию bash, add_to_path()
которая добавляет каталог, только если его там нет. Но если кто-то уже написал (или нашел) такую вещь, я не буду тратить на это время.
Ответы:
Из моего .bashrc:
Обратите внимание, что PATH уже должен быть помечен как экспортированный, поэтому повторный экспорт не требуется. Это проверяет, существует ли каталог и является ли каталогом перед его добавлением, что может вас не волновать.
Кроме того, это добавляет новый каталог в конец пути; чтобы поставить в начале, используйте
PATH="$1${PATH:+":$PATH"}"
вместоPATH=
строки выше .источник
":$PATH:"
а не просто"$PATH"
${PATH:+"$PATH:"}
${variable:+value}
означает проверить,variable
определено ли и имеет ли оно непустое значение, и дает ли оно результат оценкиvalue
. По сути, если PATH является непустым для начала, он устанавливает его в значение"$PATH:$1"
; если он пуст, он устанавливает его просто"$1"
(обратите внимание на отсутствие двоеточия).В продолжение ответа Гордона Дэвиссона, это поддерживает несколько аргументов
Таким образом, вы можете сделать pathappend path1 path2 path3 ...
За предлог,
Подобно pathappend, вы можете сделать
pathprepend path1 path2 path3 ...
источник
pathprepend P1 P2 P3
и в итоге получитьPATH=P1:P2:P3
. Чтобы получить такое поведение, изменитеfor ARG in "$@" do
наfor ((i=$#; i>0; i--)); do ARG=${!i}
Вот кое-что из моего ответа на этот вопрос в сочетании со структурой функции Дуга Харриса. Он использует регулярные выражения Bash:
источник
$1
вместо${1}
Поместите это в комментарии к выбранному ответу, но комментарии, кажется, не поддерживают форматирование PRE, поэтому добавьте ответ здесь:
@ gordon-davisson Я не большой поклонник ненужных цитат и конкатенации. Предполагая, что вы используете версию bash> = 3, вы можете вместо этого использовать встроенные в bash регулярные выражения и сделать:
Это правильно обрабатывает случаи, когда в каталоге или PATH есть пробелы. Возникает вопрос, достаточно ли медленен встроенный в bash движок регулярных выражений, чтобы это могло быть менее эффективным, чем конкатенация и интерполяция строк, которую делает ваша версия, но почему-то это кажется мне более эстетически чистым.
источник
formatting using the backtick
только, но вы не получите никакого достойного контроля над абзацами.unnecessary quoting
подразумевает, что вы заранее знаете, что$PATH
это не ноль."$PATH"
делает это нормально, независимо от того, является ли PATH нулевым или нет. Аналогично, если$1
содержит символы, которые могут запутать анализатор команд. Помещение регулярного выражения в кавычки"(^|:)$1(:|$)"
предотвращает это.[[
и]]
. Я предпочитаю , чтобы цитировать все , что может понадобиться , чтобы быть в кавычках, если это не вызывает его на провал, но я считаю , что он прав, и что котировки на самом деле не нужны вокруг$PATH
. С другой стороны, мне кажется, что вы правы$1
.Если вам нужно, чтобы $ HOME / bin появлялся ровно один раз в начале вашего $ PATH, и нигде больше, не принимайте никаких заменителей.
источник
PATH=${PATH/"
... а неPATH=${PATH//"
... чтобы заставить его работать.$1
является единственным входом (без двоеточий). Запись становится в два раза.Вот альтернативное решение, которое имеет дополнительное преимущество удаления избыточных объектов:
Единственный аргумент этой функции добавляется к PATH, и первый экземпляр той же строки удаляется из существующего пути. Другими словами, если каталог уже существует в пути, он продвигается вперед, а не добавляется как дубликат.
Функция работает, добавляя двоеточие к пути, чтобы гарантировать, что все записи имеют двоеточие спереди, а затем добавляя новую запись к существующему пути, удаляя эту запись. Последняя часть выполняется с использованием
${var//pattern/sub}
обозначения Bash ; см. руководство по bash для более подробной информации.источник
/home/robert
в себеPATH
и в себеpathadd /home/rob
.Вот мой (я полагаю, он был написан Оскаром, системным администратором моей старой лаборатории много лет назад), он был в моем bashrc целую вечность. Он имеет дополнительное преимущество, позволяя вам добавлять или добавлять новый каталог по желанию:
Использование:
источник
Для предваряющих мне нравится решение @ Russell, но есть небольшая ошибка: если вы попытаетесь добавить что-то вроде "/ bin" к пути "/ sbin: / usr / bin: / var / usr / bin: / usr / local / bin: / usr / sbin "он заменяет" / bin: "3 раза (когда он вообще не совпадал). Объединяя исправление для этого с добавлением решения от @ gordon-davisson, я получаю это:
источник
Простой псевдоним как этот ниже должен сделать трюк:
Все, что он делает, это разделяет путь на символе: и сравнивает каждый компонент с аргументом, который вы передаете. Grep проверяет полное совпадение строки и выводит счетчик.
Пример использования:
Замените команду echo на addToPath или похожий псевдоним / функцию.
источник
См. Как избежать дублирования переменной пути в csh? на StackOverflow за один набор ответов на этот вопрос.
источник
Вот что я взбил:
Сейчас в .bashrc у меня есть:
Обновленная версия после комментария о том, что мой оригинал не будет обрабатывать каталоги с пробелами (спасибо за этот вопрос за указание использовать
IFS
):источник
PATH
содержит пробелы,*
,?
или[
...]
.Documents and Settings
иProgram Files
), но Unix поддерживает имена путей, содержащие пробелы, еще до появления Windoze.Я немного удивлен, что никто еще не упомянул об этом, но вы можете использовать,
readlink -f
чтобы преобразовать относительные пути в абсолютные и добавить их в PATH как таковые.Например, чтобы улучшить ответ Гийома Перро-Аршамбо,
становится
1. Основы - что хорошего это делает?
Команда
readlink -f
(среди прочего) преобразует относительный путь в абсолютный путь. Это позволяет вам сделать что-то вроде2. Почему мы дважды тестируемся на наличие PATH?
Хорошо, рассмотрим приведенный выше пример. Если пользователь говорит из каталога во второй раз, будет . Конечно, не будет присутствовать в . Но тогда будет установлено значение (эквивалент абсолютного пути ), который уже находится в . Поэтому нам нужно избегать добавления во второй раз.
pathappend .
/path/to/my/bin/dir
ARG
.
.
PATH
ARGA
/path/to/my/bin/dir
.
PATH
/path/to/my/bin/dir
PATH
Возможно, что еще более важно, основная цель
readlink
, как следует из названия, состоит в том, чтобы посмотреть на символическую ссылку и прочитать путь, который она содержит (то есть указывает на). Например:Теперь, если вы говорите
pathappend /usr/lib/perl/5.14
, и у вас уже есть/usr/lib/perl/5.14
в вашей PATH, ну, это нормально; мы можем просто оставить все как есть. Но, если его/usr/lib/perl/5.14
еще нет в PATH, мы вызываемreadlink
и получаемARGA
=/usr/lib/perl/5.14.2
, а затем добавляем это кPATH
. Но подождите минуту - если вы уже сказалиpathappend /usr/lib/perl/5.14
, значит, у вас уже есть/usr/lib/perl/5.14.2
PATH, и, опять же, мы должны проверить это, чтобы не добавлять его воPATH
второй раз.3. В чем дело
if ARGA=$(readlink -f "$ARG")
?В случае, если неясно, эта строка проверяет,
readlink
успешно ли . Это просто хорошая, защитная практика программирования. Если мы собираемся использовать вывод команды m как часть команды n (где m < n ), целесообразно проверить, не завершилась ли команда m, и обработать это каким-либо образом. Я не думаю, что, скорее всего,readlink
это потерпит неудачу, но, как обсуждалось в разделе Как получить абсолютный путь к произвольному файлу из OS X и других областей,readlink
является изобретением GNU. Он не указан в POSIX, поэтому его доступность в Mac OS, Solaris и других не-Linux Unix-системах вызывает сомнения. (На самом деле, я только что прочитал комментарий, который говорит:readlink -f
похоже, не работает на Mac OS X 10.11.6, ноrealpath
работает «из коробки» ». Итак, если вы работаете в системе, которая не имеетreadlink
или гдеreadlink -f
не работает, вы можете изменить это использование скриптаrealpath
.) Установив сеть безопасности, мы сделаем наш код несколько более переносимым.Конечно, если вы находитесь в системе, которая не имеет
readlink
(илиrealpath
), вы не захотите делать .pathappend .
Второй
-d
тест ([ -d "$ARGA" ]
) действительно, вероятно, не нужен. Я не могу придумать ни одного сценария, в котором$ARG
каталог являетсяreadlink
успешным, но$ARGA
не является каталогом. Я просто скопировал и вставил первоеif
утверждение, чтобы создать третье, и оставил там-d
тест из-за лени.4. Любые другие комментарии?
Да уж. Как и многие другие ответы здесь, этот тест проверяет, является ли каждый аргумент каталогом, обрабатывает его, если он есть, и игнорирует его, если это не так. Это может (или не может) быть адекватным, если вы используете
pathappend
только в «.
» файлах (например,.bash_profile
и.bashrc
) и других скриптах. Но, как показал этот ответ (выше), вполне возможно использовать его в интерактивном режиме. Вы будете очень озадачены, если вы делаетеКак я уже говорил выше, это хорошая практика для обработки ошибок. Вот пример:
источник
readlink -f "$ARG"
. (2) Я не знаю, почему это произошло (особенно после-d "$ARG"
успешного прохождения теста), но вы можете проверить,readlink
провалился ли он . (3) Вы, кажется, упускаете из видуreadlink
основную функцию - сопоставить имя символической ссылки с «реальным именем файла». Если (например)/bin
символическая ссылка на/bin64
, то повторные вызовыpathappend /bin
могут привести к произнесению PATH…:/bin64:/bin64:/bin64:/bin64:…
. Вероятно, вам следует (также) проверить, есть ли новое значение$ARG
вPATH
..
я считаю , что в моем примере это можно считать каноническим именем файла. Верный?readlink
имя явно подразумевает его назначение - оно смотрит на символическую ссылку и считывает путь, который она содержит (то есть указывает на). (2) Ну, я сказал, что не знаю, почему неreadlink
получится. Я сделал общее замечание, что если сценарий или функция содержит несколько команд, а команда n гарантированно потерпит крах (или вообще не имеет смысла), если команда m не выполнена (где m < n ), целесообразно проверить , не завершилась ли команда m, и обработать ее каким-то образом - по крайней мере, ... (продолжение)readlink
может произойти сбой, если (a) каталог был переименован или удален (другим процессом) между вашими вызовамиtest
иreadlink
, или (b) если/usr/bin/readlink
был удален (или поврежден). (3) Вы, кажется, упускаете мою точку зрения. Я не призываю вас дублировать другие ответы; Я говорю, что, проверяя, находится ли оригиналARG
(из командной строки), уже в немPATH
, но не повторяя проверку новогоARG
(вывод изreadlink
), ваш ответ неполон и, следовательно, неверен. … (Продолжение)источник
Этот способ отлично работает:
источник
Мои версии менее осторожны с пустыми путями и настаивают на правильности путей и каталогов, чем некоторые, опубликованные здесь, но я нахожу большую коллекцию prepend / append / clean / unique-ify / etc. Функции оболочки должны быть полезны для манипулирования путями. Все, в их текущем состоянии, здесь: http://pastebin.com/xS9sgQsX (отзывы и улучшения очень приветствуются!)
источник
Вы можете использовать perl one liner:
Вот это в bash:
источник
Я немного изменил ответ Гордона Дэвиссона, чтобы использовать текущий каталог, если он не указан. Таким образом, вы можете просто сделать
padd
из каталога, который вы хотите добавить в ваш путь.источник
Вы можете проверить, была ли установлена пользовательская переменная, иначе установить ее, а затем добавить новые записи:
Конечно, эти записи могут быть дублированы, если они добавлены другим скриптом, например
/etc/profile
.источник
Этот скрипт позволяет добавить в конце
$PATH
:Или добавить в начале
$PATH
:источник
Вот POSIX-совместимый способ.
Он списан из Гийого Перро-Archambault «s ответа на этот вопрос и mike511 » s ответа здесь .
ОБНОВЛЕНИЕ 2017-11-23: Исправлена ошибка в @Scott
источник
/etc/profile
. Каталог, который вы пытаетесь добавить в PATH, может быть уже там несколько раз , и ваш код его захлебывается. … (Продолжение)/a/ck
к/b:/a/ck:/tr:/a/ck
, вы получите/a/ck:/b:/a/ck:/tr:/tr:/a/ck
.