Опубликовано 2 декабря 2023 г.
Обсуждать:
Форум FreeBSD
|
Реддит
Посмотреть эту статью файлы примеров
Мне нравится писать сценарии оболочки, но одна вещь, которая беспокоит меня уже много лет, это то, что я не знаю, как включать относительные сценарии. Я столкнулся с тремя ключевыми проблемами:
. relative/script.sh
зависит от директории вызова.- Символическая ссылка на команду приводит к несогласованному имени и местоположению команды.
- Почти все интернет-обсуждения сценариев оболочки посвящены Bash, тогда как я использую
sh(1)
на FreeBSD (также известной как оболочка Bourne).
доктор: Решение
Использовать $(dirname $(realpath $0))
в ваших командных файлах. realpath(1)
Проблема 1: директория вызова имеет значение
Очевидный способ включения относительных файлов: . relative/script.sh
. Имеем следующую файловую структуру:
.
├── bin
│ └── hello.sh
└── lib
└── libhello.sh
бин/hello.sh:
#!/bin/sh
. lib/libhello.sh
hello
lib/libhello.sh:
hello() {
echo hello, world
}
Бег ./bin/hello.sh
работает так, как ожидалось, тогда как cd bin && ./hello.sh
терпит неудачу:
./bin/hello.sh
hello, world
cd bin && ./hello.sh
.: cannot open lib/libhello.sh: No such file or directory
Нам нужен какой-то способ поиска относительно пути к сценарию, а не каталога вызова.
Наивное решение: использовать $0
чтобы найти местоположение сценария
$0
возвращает имя вызванной команды, включая любой префикс каталога. Мы можем использовать его для запроса относительных файлов:
бин/hello.sh:
#!/bin/sh
LIB=$(dirname $0)/../lib
. $LIB/libhello.sh
hello
Теперь команда выполняется успешно, независимо от того, из какого каталога мы ее вызываем:
./bin/hello.sh
hello, world
cd bin && ./hello.sh
hello, world
Однако, $0
— это имя команды, передаваемой в оболочку, которое может не быть реальным командным файлом при использовании символических ссылок.
Проблема 2. Символические ссылки делают имя сценария ненадежным.
Ссылки $0
работает, пока мы не создадим символическую ссылку на файл. Это новая файловая структура:
.
├── actual-hello
│ ├── actual-hello.sh
│ └── libhello.sh
└── bin
└── hello.sh -> ../actual-hello/actual-hello.sh
Сейчас работает ./bin/hello.sh
пытается включить файл относительно bin/hello.sh
когда это должно быть относительно actual-hello/actual-hello.sh
.
К счастью, FreeBSD дает нам realpath(1)
чтобы идентифицировать реальный файл, на который ссылается символическая ссылка.
Решение: использовать realpath(1)
исходный код относительно реального файла
актуальный-привет/актуальный-привет.sh:
#!/bin/sh
LIB=$(dirname $(realpath $0))
. $LIB/libhello.sh
hello
$(realpath $0)
возвращает путь к реальному файлу, поэтому теперь мы можем использовать источник относительно него. Наша символическая ссылка работает независимо от каталога вызова:
./bin/hello.sh
hello, world
cd bin && ./hello.sh
hello, world
Бонусное решение: вспомогательная функция lib.
Теперь, когда мы знаем основную технику, мы можем определить BASE
var и напишем нашу библиотеку оболочки относительно нее. Вот структура файла:
.
├── actual-hello
│ ├── bin
│ │ └── actual-hello.sh
│ └── lib
│ ├── libhello.sh
│ └── libhelper.sh
└── bin
└── hello.sh -> ../actual-hello/bin/actual-hello.sh
актуальный-привет/bin/actual-hello.sh:
#!/bin/sh
BASE=$(dirname $(realpath $0))/..
. $BASE/lib/libhelper.sh
require_lib "hello"
hello
актуальный-привет/lib/libhelper.sh:
: ${BASE:?}
LIB=$BASE/lib
require_lib() {
. $LIB/lib${1}.sh
}
Заключение
Можно написать очень сильно мощный инструменты используя сценарии оболочки и модульизируйте свой код. Оболочка Bourne не предоставляет четкого механизма ссылки на относительные файлы. Установив базовый каталог командного файла, вы можете надежно ссылаться на соответствующие сценарии оболочки.
2023-12-04 05:21:09
1701675208
#Относительный #сценарий #оболочки #включает #себя #Realpath #во #FreeBSD