Что такое bash эквивалент Python `if __name__ == '__main __'`?
В Bash я бы хотел иметь возможность как создать сценарий, так и выполнить файл. Что такое Bash, эквивалентный Python, if __name__ == '__main__'
?
Я не нашел легкодоступного вопроса/решения по этой теме в Stackoverflow (я подозреваю, что задаю вопрос таким образом, чтобы он не соответствовал существующему вопросу/ответу, но это наиболее очевидный способ выражения фразы вопрос из-за моего опыта работы с Python).
о возможном дублировании вопроса (если бы у меня было больше времени, я бы написал более короткий ответ):
В связанном с вопросом вопросе "Как определить, получен ли сценарий", но в этом вопросе "как создать сценарий bash, который может быть получен и запущен как сценарий?". Ответ на этот вопрос может использовать некоторые аспекты предыдущего вопроса, но имеет следующие дополнительные требования/вопросы:
- Как только вы обнаружите, что сценарий получен, что является лучшим способом не запускать сценарий (и избежать непреднамеренных побочных эффектов (кроме импорта интересующих функций), таких как добавление/удаление/изменение среды/переменных)
- Как только вы обнаружите, что сценарий выполняется вместо источника, каков канонический способ реализации вашего сценария (поместить его в функцию? Или, может быть, просто поместить его после оператора if? Если вы поместите его после оператора if, он будет иметь влияет?
- большинство поисковых запросов в Google, которые я нашел в Bash, не охватывают эту тему (сценарий bash, который может быть как получен, так и выполнен), каков канонический способ реализовать это? тема не освещена, потому что это не рекомендуется или плохо делать? есть ли ошибки?
Ответы
Ответ 1
Решение:
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "[email protected]"
fi
Я добавил этот ответ, потому что мне нужен ответ, написанный в стиле для имитации Python if __name__ == '__main__'
, но в Bash.
Относительно использования BASH_SOURCE
vs $_
. Я использую BASH_SOURCE
, потому что он кажется более надежным, чем $_
(link1, link2).
Вот пример, который я тестировал/проверял с помощью двух скриптов Bash.
script1.sh с функцией xyz()
:
#!/bin/bash
xyz() {
echo "Entering script1 xyz()"
}
main() {
xyz
echo "Entering script1 main()"
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "[email protected]"
fi
script2.sh, который пытается вызвать функцию xyz()
:
#!/bin/bash
source script1.sh
xyz
Ответ 2
Нет. Обычно я использую это:
#!/bin/bash
main()
{
# validate parameters
echo "In main: [email protected]"
# your code here
}
main "[email protected]"
Если вы хотите узнать, является ли этот script source
'd, просто заверните вызов main
в
if [[ "$_" != "$0" ]]; then
echo "Script is being sourced, not calling main()"
else
echo "Script is a subshell, calling main()"
main "[email protected]"
fi
Ссылка: Как определить, есть ли script источник
Ответ 3
Использовать FUNCNAME
Способ 1: проверить FUNCNAME[0]
(Bash 4. 3+)
#!/bin/bash
_main(){
echo hello
}
if [[ ${FUNCNAME[0]} == "main" ]]; then
_main
fi
Пример выполнения:
$ bash funcname_test.sh
hello
$ source funcname_test.sh
$ _main
hello
Я не уверен, как я наткнулся на это. man bash не очень хорошо описывает его функциональность, но вот что он на самом деле делает:
- Выполненный скрипт:
${FUNCNAME[0]}
является main
- Источник сценария:
${FUNCNAME[0]}
является source
- Функция оболочки:
${FUNCNAME[0]}
- это имя функции
Способ 2: проверить FUNCNAME[1]
внутри функции (Bash 4.2)
В Bash 4.2 FUNCNAME
доступно только внутри функции, где FUNCNAME[0]
- это имя функции, а FUNCNAME[1]
- имя вызывающей стороны. Таким образом, для функции верхнего уровня FUNCNAME[1]
будет main
в исполняемом скрипте или source
в source
скрипте.
Этот пример должен работать так же, как пример выше.
#!/bin/bash
get_funcname_1(){
printf '%s\n' "${FUNCNAME[1]}"
}
_main(){
echo hello
}
if [[ $(get_funcname_1) == main ]]; then
_main
fi
Ответ 4
Для идиоматического способа Bash сделать это, вы можете использовать return
следующим образом:
_main(){
echo hello
}
# End sourced section
return 2> /dev/null
_main
Пример выполнения:
$ bash return_test.sh
hello
$ source return_test.sh
$ _main
hello
Если сценарий получен, return
вернется к родителю (конечно), но если скрипт будет выполнен, return
выдаст ошибку, и скрипт продолжит выполнение.
Я проверил это на GNU Bash 4.2 до 4.4
Это основано на части ответа mr.spuratic о том, как определить, что сценарий получен.
Предупреждение: это не работает в большинстве других оболочек.
Ответ 5
Я использовал следующую конструкцию в нижней части всех моих скриптов:
[[ "$(caller)" != "0 "* ]] || main "[email protected]"
Все остальное в script определено в функции или является глобальной переменной.
caller
документируется как "Возврат контекста текущего вызова подпрограммы". При получении script результат вызывающего абонента начинается с номера строки script sourcing this. Если этот script не используется, он начинается с "0 "
Причина, по которой я использую !=
и ||
вместо =
и &&
, заключается в том, что последняя приведет к тому, что script вернет false при поиске. Это может привести к выходу внешнего script, если он работает под set -e
.
Обратите внимание, что я знаю, что это работает с bash. Он не будет работать с оболочкой posix. Я не знаю о других оболочках, таких как ksh или zsh.