Я немного удивлен, что никто еще не упомянул об этом, но вы можете использовать, readlink -f
чтобы преобразовать относительные пути в абсолютные и добавить их в PATH как таковые.
Например, чтобы улучшить ответ Гийома Перро-Аршамбо,
pathappend() {
for ARG in "$@"
do
if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]; then
PATH="${PATH:+"$PATH:"}$ARG"
fi
done
}
становится
pathappend() {
for ARG in "$@"
do
if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]
then
if ARGA=$(readlink -f "$ARG") #notice me
then
if [ -d "$ARGA" ] && [[ ":$PATH:" != *":$ARGA:"* ]]
then
PATH="${PATH:+"$PATH:"}$ARGA"
fi
else
PATH="${PATH:+"$PATH:"}$ARG"
fi
fi
done
}
1. Основы - что хорошего это делает?
Команда readlink -f
(среди прочего) преобразует относительный путь в абсолютный путь. Это позволяет вам сделать что-то вроде
$ cd / path / to / my / bin / dir
$ pathappend .
$ echo "$ PATH"
<your_old_path> : / path / to / my / bin / dir
2. Почему мы дважды тестируемся на наличие PATH?
Хорошо, рассмотрим приведенный выше пример. Если пользователь говорит
из каталога во второй раз,
будет . Конечно, не будет присутствовать в . Но тогда будет установлено значение
(эквивалент абсолютного пути ), который уже находится в . Поэтому нам нужно избегать добавления во второй раз.pathappend .
/path/to/my/bin/dir
ARG
.
.
PATH
ARGA
/path/to/my/bin/dir
.
PATH
/path/to/my/bin/dir
PATH
Возможно, что еще более важно, основная цель readlink
, как следует из названия, состоит в том, чтобы посмотреть на символическую ссылку и прочитать путь, который она содержит (то есть указывает на). Например:
$ ls -ld /usr/lib/perl/5.14
-rwxrwxrwx 1 root root Sep 3 2015 /usr/lib/perl/5.14 -> 5.14.2
$ readlink /usr/lib/perl/5.14
5.14.2
$ readlink -f /usr/lib/perl/5.14
/usr/lib/perl/5.14.2
Теперь, если вы говорите 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
) и других скриптах. Но, как показал этот ответ (выше), вполне возможно использовать его в интерактивном режиме. Вы будете очень озадачены, если вы делаете
$ pathappend /usr/local/nysql/bin
$ mysql
-bash: mysql: command not found
Вы заметили, что я сказал nysql
в pathappend
команде, а не mysql
? И это pathappend
ничего не говорит; он просто молча проигнорировал неверный аргумент?
Как я уже говорил выше, это хорошая практика для обработки ошибок. Вот пример:
pathappend() {
for ARG in "$@"
do
if [ -d "$ARG" ]
then
if [[ ":$PATH:" != *":$ARG:"* ]]
then
if ARGA=$(readlink -f "$ARG") #notice me
then
if [[ ":$PATH:" != *":$ARGA:"* ]]
then
PATH="${PATH:+"$PATH:"}$ARGA"
fi
else
PATH="${PATH:+"$PATH:"}$ARG"
fi
fi
else
printf "Error: %s is not a directory.\n" "$ARG" >&2
fi
done
}