Я немного удивлен, что никто еще не упомянул об этом, но вы можете использовать, 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/dirARG..PATHARGA/path/to/my/bin/dir.PATH/path/to/my/bin/dirPATH
Возможно, что еще более важно, основная цель 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.2PATH, и, опять же, мы должны проверить это, чтобы не добавлять его во 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
}