Обычно вы включаете скрипт с помощью «source»
например:
main.sh:
#!/bin/bash
source incl.sh
echo "The main script"
incl.sh:
echo "The included script"
Результат выполнения "./main.sh":
The included script
The main script
... Теперь, если вы попытаетесь выполнить этот скрипт оболочки из другого места, он не сможет найти включение, если оно не находится на вашем пути.
Какой хороший способ убедиться, что ваш сценарий может найти сценарий включения, особенно если, например, сценарий должен быть переносимым?
Ответы:
Я стараюсь, чтобы все мои сценарии были связаны друг с другом. Таким образом, я могу использовать dirname:
источник
which $0
будет полезноBASH_SOURCE
массиве и о том, как первый элемент в этом массиве всегда указывает на текущий источник.Я знаю, что опаздываю на вечеринку, но это должно работать независимо от того, как вы запускаете скрипт и использует исключительно встроенные функции:
.
(точка) - это псевдонимsource
,$PWD
путь к рабочему каталогу ,BASH_SOURCE
переменная массива, членами которой являются исходные имена файлов,${string%substring}
удаляет кратчайшее совпадение $ substring из задней части $ stringисточник
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
нужна линия ? Я могу найти в этом необходимость, если команды будут вставлены в приглашение bash для запуска. Тем не менее, если он работает в контексте файла скрипта, я не вижу в этом необходимости ...source
s (я имею в виду, если вы создаетеsource
скрипт, который находитсяsource
в другом каталоге и т. Д., Он все еще работает).${BASH_SOURCE[0]}
как вы хотите только последний звонок? Также использованиеDIR=$(dirname ${BASH_SOURCE[0]})
позволит вам избавиться от if-условияАльтернатива:
является:
.. преимущество заключается в отсутствии зависимости от dirname, которое не является встроенной командой (и не всегда доступно в эмуляторах)
источник
basePath=$(dirname $0)
дал мне пустое значение, когда содержащий файл сценария получен.Если он находится в том же каталоге, вы можете использовать
dirname $0
:источник
$0
является./t.sh
и Dirname возвращается.
; 2) послеcd bin
вернул.
не правильно.$BASH_SOURCE
не лучшеsource "$(dirname $0)/incl.sh"
работает в тех случаяхЯ думаю, что лучший способ сделать это - использовать метод Криса Борана, НО вы должны вычислять MY_DIR следующим образом:
Чтобы процитировать man-страницы для readlink:
Я никогда не сталкивался с случаем использования, где
MY_DIR
неправильно вычисляется. Если вы обращаетесь к своему сценарию через символическую ссылку,$PATH
он работает.источник
$0
напрямую?/home/you/script.sh
Вы можетеcd /home
запустить свой сценарий оттуда, так как./you/script.sh
в этом случаеdirname $0
он вернется,./you
а другой сценарий завершится неудачейMY_DIR=$(dirname $(readlink -f $0)); source $MY_DIR/incl.sh
Комбинация ответов на этот вопрос обеспечивает наиболее надежное решение.
Он работал для нас в сценариях промышленного уровня с отличной поддержкой зависимостей и структуры каталогов:
Метод поддерживает все это:
readlink
)${BASH_SOURCE[0]}
является более надежным, чем$0
источник
readlink -f "${BASH_SOURCE[0]}" 2>/dev/null||echo $0
если ваша ссылка для чтения BusyBox v1.01DIR=$(dirname $(readlink -f "${BASH_SOURCE[0]}" 2>/dev/null||echo $0)) # https://stackoverflow.com/a/34208365/
источник
./incl.sh
разрешается по тому же пути, что иcd
+pwd
. Так в чем же преимущество смены каталога?Это работает, даже если скрипт получен:
источник
BASH_SOURCE
- это массив путей, соответствующих стеку вызовов. Первый элемент соответствует самому последнему сценарию в стеке, который является текущим выполняемым сценарием. На самом деле,$BASH_SOURCE
вызываемая как переменная по умолчанию расширяется до первого элемента, поэтому[0]
здесь нет необходимости. Смотрите эту ссылку для деталей.1. Neatest
Я изучил почти каждое предложение, и вот самое подходящее, которое сработало для меня:
script_root=$(dirname $(readlink -f $0))
Это работает даже тогда, когда скрипт имеет символическую ссылку на
$PATH
каталог.Смотрите это в действии здесь: https://github.com/pendashteh/hcagent/blob/master/bin/hcagent
2. Самый крутой
Это на самом деле из другого ответа на этой самой странице, но я тоже добавляю его в свой ответ!
2. Самый надежный
В качестве альтернативы, в редком случае, когда это не сработало, вот пуленепробиваемый подход:
Вы можете увидеть это в действии в
taskrunner
источнике: https://github.com/pendashteh/taskrunner/blob/master/bin/taskrunnerНадеюсь, это поможет кому-то там :)
Кроме того, пожалуйста, оставьте его в качестве комментария, если он не работает для вас, и укажите вашу операционную систему и эмулятор. Спасибо!
источник
Вам нужно указать расположение других скриптов, другого пути нет. Я бы порекомендовал настраиваемую переменную вверху вашего скрипта:
В качестве альтернативы вы можете настаивать на том, чтобы пользователь поддерживал переменную среды, указывающую, где находится ваша программа, например, PROG_HOME или что-то подобное. Это может быть предоставлено пользователю автоматически путем создания сценария с этой информацией в /etc/profile.d/, который будет запрашиваться при каждом входе пользователя в систему.
источник
Я бы посоветовал вам создать сценарий setenv, единственной целью которого является предоставление местоположений для различных компонентов в вашей системе.
Все остальные сценарии будут исходить из этого сценария, чтобы все расположения были общими для всех сценариев с использованием сценария setenv.
Это очень полезно при запуске cronjobs. Вы получаете минимальную среду при запуске cron, но если вы сначала включите все сценарии cron, включающие сценарий setenv, то сможете контролировать и синхронизировать среду, в которой вы хотите, чтобы cronjobs выполнялся.
Мы использовали такую технику на нашей сборочной обезьяне, которая использовалась для непрерывной интеграции в рамках проекта около 2000 kSLOC.
источник
Ответ Стива, безусловно, является правильной техникой, но его следует реорганизовать так, чтобы ваша переменная installpath находилась в отдельном скрипте среды, в котором сделаны все такие объявления.
Затем все сценарии исходят из этого сценария и должны изменить путь установки, вам нужно изменить его только в одном месте. Делает вещи более, э, будущее. Боже, я ненавижу это слово! (-:
Кстати, вы действительно должны ссылаться на переменную, используя $ {installpath}, используя ее так, как показано в вашем примере:
Если фигурные скобки пропущены, некоторые оболочки попытаются расширить переменную "installpath / incl.sh"!
источник
Shell Script Loader является моим решением для этого.
Он предоставляет функцию с именем include (), которая может вызываться много раз во многих сценариях для ссылки на один сценарий, но загружает сценарий только один раз. Функция может принимать полные или частичные пути (сценарий ищется в пути поиска). Также предусмотрена аналогичная функция load (), которая загружает сценарии безоговорочно.
Это работает для bash , ksh , pd ksh и zsh с оптимизированными скриптами для каждого из них; и другие оболочки, которые в общем совместимы с исходным sh, такие как ash , dash , heirloom sh и т. д., с помощью универсального сценария, который автоматически оптимизирует его функции в зависимости от функций, которые может обеспечить оболочка.
[Пример наград]
start.sh
Это необязательный стартовый скрипт. Размещение методов запуска здесь просто для удобства и может быть помещено в основной скрипт. Этот сценарий также не нужен, если сценарии должны быть скомпилированы.
main.sh
a.sh
b.sh
вывод:
Что лучше всего, сценарии на его основе также могут быть скомпилированы для формирования единого сценария с доступным компилятором.
Вот проект, который использует его: http://sourceforge.net/p/playshell/code/ci/master/tree/ . Он может работать переносимо с или без компиляции скриптов. Может также произойти компиляция для создания одного скрипта, что полезно при установке.
Я также создал более простой прототип для любой консервативной партии, которая может хотеть иметь краткое представление о том, как работает скрипт реализации: https://sourceforge.net/p/loader/code/ci/base/tree/loader-include-prototype .bash . Он небольшой, и любой может просто включить код в свой основной скрипт, если захочет, если его код предназначен для работы с Bash 4.0 или новее, и он также не использует
eval
.источник
eval
кода для загрузки зависимостей. Ойeval
блоков внизу всегда запускается. Так что, нужно ли это или нет, он обязательно используетeval
.eval
это чистое зло, и не знают, как его использовать.eval
это зло.Лично поместите все библиотеки в
lib
папку и используйтеimport
функцию для их загрузки.структура папок
script.sh
содержаниеОбратите внимание, что эта функция импорта должна быть в начале вашего скрипта, а затем вы можете легко импортировать ваши библиотеки следующим образом:
Добавьте одну строку вверху каждой библиотеки (т.е. utils.sh):
Теперь у вас есть доступ к функциям внутри
utils.sh
иrequirements.sh
изscript.sh
TODO: написать компоновщик для создания одного
sh
файлаисточник
Использование source или $ 0 не даст вам реальный путь к вашему сценарию. Вы можете использовать идентификатор процесса скрипта, чтобы получить его реальный путь
Я использую этот скрипт, и он всегда служил мне хорошо :)
источник
Я поместил все свои сценарии запуска в каталог .bashrc.d. Это обычная техника в таких местах, как /etc/profile.d и т. Д.
Проблема с решением с использованием globbing ...
... есть ли у вас список файлов, который "слишком длинный". Подход, как ...
... работает, но не меняет окружающую среду по желанию.
источник
Конечно, каждому свое, но я думаю, что блок ниже довольно солидный. Я считаю, что это включает «лучший» способ найти каталог и «лучший» способ вызвать другой скрипт bash:
Так что это может быть «лучший» способ включить другие скрипты. Это основано на другом «лучшем» ответе, который сообщает bash-скрипту, где он хранится
источник
Это должно работать надежно:
источник
нам просто нужно найти папку, в которой хранятся наши incl.sh и main.sh; просто измените ваш main.sh с этим:
main.sh
источник
echo
и неправильное использованиеsed
«Sg
опции. -1.SCRIPT_DIR=$(echo "$0" | sed "s/${SCRIPT_NAME}//")
а затемsource "${SCRIPT_DIR}incl.sh"
Соответственно
man hier
подходящее место для сценария включает в себя/usr/local/lib/
Лично я предпочитаю
/usr/local/lib/bash/includes
включать. Существует библиотека bash-helper для включения библиотек таким образом:источник
Вы также можете использовать:
источник