Я трохи здивований, що ще ніхто про це не згадав, але ви можете використовувати 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 / шлях / до / мій / бін / реж
$ pathappend .
$ echo "$ PATH"
<your_old_path> : / шлях / до / мій / бін / реж
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ПАТ, то це добре; ми можемо просто залишити його таким, яким він є. Але, якщо цього /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вдруге.
3. З чим угоди if ARGA=$(readlink -f "$ARG")?
Якщо це незрозуміло, цей рядок перевіряє, чи readlinkвдалося це зробити. Це просто хороша практика оборонного програмування. Якщо ми збираємось використовувати вихід з команди m
як частину команди n (де m < n ), доцільно перевірити, чи не вдалося команду m та якось обробити це. Я не думаю, що це, ймовірно, readlinkне вдасться, але, як обговорювалось у розділі Як отримати абсолютний шлях довільного файлу з ОС X
та інших країн, readlinkце винахід GNU. Це не визначено в POSIX, тому його доступність у Mac OS, Solaris та інших нелінуксних 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
}