Как определить, если сценарий находится в исходном состоянии
у меня есть сценарий, где я не хочу его называть exit Если это источник.
Я подумал проверить, если == bash но это имеет проблемы, если сценарий получен из другого сценария, или если пользователь создает его из другой оболочки, например ksh.
есть ли надежный способ обнаружения, если сценарий был произведен?
16 ответов:
это, кажется, переносится между Bash и Korn:
[[ $_ != ]] && echo "Script is being sourced" || echo "Script is a subshell"строка, похожая на эту или назначение типа 'pathname=" $_ " (с более поздним тестом и действием), должна быть в первой строке скрипта или в строке после shebang (которая, если используется, должна быть для ksh, чтобы она работала в большинстве случаев).
Если ваша версия Bash знает о переменной массива BASH_SOURCE, попробуйте что-то вроде:
# man bash | less -p BASH_SOURCE #[[ ${BASH_VERSINFO[0]} -le 2 ]] && echo 'No BASH_SOURCE array variable' && exit 1 [[ "${BASH_SOURCE[0]}" != "" ]] && echo "script ${BASH_SOURCE[0]} is being sourced ..."
после прочтения ответа @ DennisWilliamson, есть некоторые вопросы, см. ниже:
как этот вопрос стоять КШиБаш, в этом ответе есть еще одна часть, касающаяся КШ... увидеть ниже.
простой Баш путь
[ "" = "$BASH_SOURCE" ]давайте попробуем (на лету, потому что это Баш мог ; -):
source <(echo $'#!/bin/bash [ "" = "$BASH_SOURCE" ] && v=own || v=sourced; echo "process $$ is $v (, $BASH_SOURCE)" ') process 29301 is sourced (bash, /dev/fd/63) bash <(echo $'#!/bin/bash [ "" = "$BASH_SOURCE" ] && v=own || v=sourced; echo "process $$ is $v (, $BASH_SOURCE)" ') process 16229 is own (/dev/fd/63, /dev/fd/63)я использую
sourceвместо.для читаемость (как.- это псевдоним дляsource):. <(echo $'#!/bin/bash [ "" = "$BASH_SOURCE" ] && v=own || v=sourced; echo "process $$ is $v (, $BASH_SOURCE)" ') process 29301 is sourced (bash, /dev/fd/63)обратите внимание, что номер процесса не меняется, пока процесс остается источников:
echo $$ 29301почему бы не использовать
$_ ==сравнениедля обеспечения многих случаев, я начинаю писать правда сценарий:
#!/bin/bash # As $_ could be used only once, uncomment one of two following lines #printf '_="%s", 0="%s" and BASH_SOURCE="%s"\n' "$_" "" "$BASH_SOURCE" [[ "$_" != "" ]] && DW_PURPOSE=sourced || DW_PURPOSE=subshell [ "" = "$BASH_SOURCE" ] && BASH_KIND_ENV=own || BASH_KIND_ENV=sourced; echo "proc: $$[ppid:$PPID] is $BASH_KIND_ENV (DW purpose: $DW_PURPOSE)"скопируйте это в файл с именем
testscript:cat >testscript chmod +x testscriptтеперь мы могли бы проверить:
./testscript proc: 25758[ppid:24890] is own (DW purpose: subshell)вот ладно.
. ./testscript proc: 24890[ppid:24885] is sourced (DW purpose: sourced) source ./testscript proc: 24890[ppid:24885] is sourced (DW purpose: sourced)это нормально.
но, для тестирования скрипта перед добавлением
-xфлаг:bash ./testscript proc: 25776[ppid:24890] is own (DW purpose: sourced)или использовать предопределенные переменные:
env PATH=/tmp/bintemp:$PATH ./testscript proc: 25948[ppid:24890] is own (DW purpose: sourced) env SOMETHING=PREDEFINED ./testscript proc: 25972[ppid:24890] is own (DW purpose: sourced)это больше не будет работать.
перемещение комментария с 5-й строки на 6-ю даст более читаемый ответ:
./testscript _="./testscript", 0="./testscript" and BASH_SOURCE="./testscript" proc: 26256[ppid:24890] is own . testscript _="_filedir", 0="bash" and BASH_SOURCE="testscript" proc: 24890[ppid:24885] is sourced source testscript _="_filedir", 0="bash" and BASH_SOURCE="testscript" proc: 24890[ppid:24885] is sourced bash testscript _="/bin/bash", 0="testscript" and BASH_SOURCE="testscript" proc: 26317[ppid:24890] is own env FILE=/dev/null ./testscript _="/usr/bin/env", 0="./testscript" and BASH_SOURCE="./testscript" proc: 26336[ppid:24890] is ownсложнее: КШ сейчас...
как я не использую КШ большое, после некоторого чтения на man-странице, есть мой пытается:
#!/bin/ksh set >/tmp/ksh-$$.logскопируйте это в
testfile.ksh:cat >testfile.ksh chmod +x testfile.kshчем запустить его два раза:
./testfile.ksh . ./testfile.ksh ls -l /tmp/ksh-*.log -rw-r--r-- 1 user user 2183 avr 11 13:48 /tmp/ksh-9725.log -rw-r--r-- 1 user user 2140 avr 11 13:48 /tmp/ksh-9781.log echo $$ 9725и видим:
diff /tmp/ksh-{9725,9781}.log | grep ^\> # OWN SUBSHELL: > HISTCMD=0 > PPID=9725 > RANDOM=1626 > SECONDS=0.001 > lineno=0 > SHLVL=3 diff /tmp/ksh-{9725,9781}.log | grep ^\< # SOURCED: < COLUMNS=152 < HISTCMD=117 < LINES=47 < PPID=9163 < PS1='$ ' < RANDOM=29667 < SECONDS=23.652 < level=1 < lineno=1 < SHLVL=2есть какая-то переменная недвижимости, полученной в наследство в источников бежать, но ничего на самом деле...
вы даже можете проверить это
$SECONDSвблизи0.000, но это обеспечит только в ручную источников случаях...вы даже можете попробовать проверить что это родитель:
поместите это в ваш
testfile.ksh:ps $PPIDчем:
./testfile.ksh PID TTY STAT TIME COMMAND 32320 pts/4 Ss 0:00 -ksh . ./testfile.ksh PID TTY STAT TIME COMMAND 32319 ? S 0:00 sshd: user@pts/4или
ps ho cmd $PPID, но это работает только для одного уровня подсессии...Извините, я не мог найти надежный способ сделать это, под КШ.
надежные решения для
bash,ksh,zsh, включая cross-shell один, плюс a достаточно надежное POSIX-совместимое решение:
номера версий приведены те, на которых функциональность была проверен - скорее всего, эти решения работают и на гораздо более ранних версиях -обратная связь приветствуется.
используя POSIX особенности только (например,
dash, который действует как/bin/shна Ubuntu), есть нет надежная путь чтобы определить, является ли сценарий источником-см. Нижнюю часть этого ответа для лучшего приближение.-е ниже приведено объяснение; версия Кросс-оболочки сложна, но она должна работать надежно:
Баш (проверено на 3.57)
[[ != "$BASH_SOURCE" ]] && sourced=1 || sourced=0КШ (проверено на 93u+)
[[ $(cd "$(dirname -- "")" && printf '%s' "${PWD%/}/")$(basename -- "") != "${.sh.file}" ]] && sourced=1 || sourced=0zsh (проверено на 5.0.5) - обязательно называть это вне функции
[[ $ZSH_EVAL_CONTEXT =~ :file$ ]] && sourced=1 || sourced=0cross-shell (bash, ksh, zsh)
([[ -n $ZSH_EVAL_CONTEXT && $ZSH_EVAL_CONTEXT =~ :file$ ]] || [[ -n $KSH_VERSION && $(cd "$(dirname -- "")" && printf '%s' "${PWD%/}/")$(basename -- "") != "${.sh.file}" ]] || [[ -n $BASH_VERSION && != "$BASH_SOURCE" ]]) && sourced=1 || sourced=0кросс-оболочки, в том числе в POSIX-функций-только снаряды (
dash,sh); не a шутка (один трубопровод) по техническим причинам и не полностью надежная (смотрите внизу):sourced=0 if [ -n "$ZSH_EVAL_CONTEXT" ]; then case $ZSH_EVAL_CONTEXT in *:file) sourced=1;; esac elif [ -n "$KSH_VERSION" ]; then [ "$(cd $(dirname -- ) && pwd -P)/$(basename -- )" != "$(cd $(dirname -- ${.sh.file}) && pwd -P)/$(basename -- ${.sh.file})" ] && sourced=1 elif [ -n "$BASH_VERSION" ]; then [ "" != "$BASH_SOURCE" ] && sourced=1 else # All other shells: examine for known shell binary filenames # Detects `sh` and `dash`; add additional shell filenames as needed. case ${0##*/} in sh|dash) sourced=1;; esac fi
объяснение:
Баш
[[ "" != "$BASH_SOURCE" ]] && sourced=1 || sourced=0
$BASH_SOURCE... Всегда содержит файл скрипта аргумент, будь то источник или нет....
- если не получены: всегда идентичны
$BASH_SOURCE- ЕСЛИ ИСТОЧНИК:
- если источник из другого сценария: сценарий с который сценарий под рукой в настоящее время источников.
- если источник в интерактивном режиме:
- как правило,
bashдля оболочки без входа в систему и-bashдля оболочки входа (например, на OSX), или, если Bash был вызван какsh, аналогичноshили-sh.- однако, если Bash был запущен (напрямую) с относительным или абсолютным путем этот путь будет отражен в
.- также обратите внимание, что можно запустить Bash (или любую программу) с произвольным значением для
, например, с помощьюexecстроение с .
КШ
[[ \ $(cd "$(dirname -- "")" && printf '%s' "${PWD%/}/")$(basename -- "") != \ "${.sh.file}" \ ]] && sourced=1 || sourced=0специальная переменная
${.sh.file}несколько аналогично$BASH_SOURCE; обратите внимание, что${.sh.file}вызывает a синтаксис в bash, zsh и dash, так что не забудьте выполнить его условно в сценариях с несколькими оболочками.в отличие от Баша,
и${.sh.file}не гарантируется ровно идентично в случае без источника, какможет быть относительные путь, в то время как${.sh.file}всегда полное путь, такдолжен быть разрешен до полного пути, прежде чем сравнивающий.
zsh
[[ $ZSH_EVAL_CONTEXT =~ :file$ ]] && sourced=1 || sourced=0
$ZSH_EVAL_CONTEXTсодержит информацию о контексте оценки-вызовите это вне функции. Внутри исходного сценария [область верхнего уровня],$ZSH_EVAL_CONTEXTзаканчивается с:file.предостережение: внутри замены команды, zsh добавляет
:cmdsubst, так что$ZSH_EVAL_CONTEXTна:file:cmdsubst$там.
использование только функций POSIX
если вы готовы убедиться предположения, вы можете сделать разумная, но не дурацкая догадка что касается того, является ли ваш скрипт источником, на основе зная имена файлов оболочек, которые могут выполнять ваш скрипт.
Примечательно, что это означает, что этот подход терпит неудачу, если ваш скрипт создается еще один скрипт.раздел "как обрабатывать исходные вызовы" в ответ мой обсуждает крайние случаи, что не может обрабатываться с помощью функций POSIX только в деталях.
этой полагается на стандартное поведение
, которыйzsh, например, совсем не выставку.таким образом, самый безопасный подход к объедините надежные, специфичные для оболочки методы выше с резервное решение для всех остальных снарядов.
кончик шляпы к Stéphane Desneux и ответ для вдохновения (преобразование моего выражения оператора кросс-оболочки в
sh-совместимыйifоператор и добавление обработчика для других оболочек).sourced=0 if [ -n "$ZSH_EVAL_CONTEXT" ]; then case $ZSH_EVAL_CONTEXT in *:file) sourced=1;; esac elif [ -n "$KSH_VERSION" ]; then [ "$(cd $(dirname -- ) && pwd -P)/$(basename -- )" != "$(cd $(dirname -- ${.sh.file}) && pwd -P)/$(basename -- ${.sh.file})" ] && sourced=1 elif [ -n "$BASH_VERSION" ]; then [ "" != "$BASH_SOURCE" ] && sourced=1 else # All other shells: examine for known shell binary filenames # Detects `sh` and `dash`; add additional shell filenames as needed. case ${0##*/} in sh|dash) sourced=1;; esac fi
The
BASH_SOURCE[]ответ (bash-3.0 и позже) кажется самым простым, хотяBASH_SOURCE[]и не документировано для работы вне тела функции (в настоящее время это работает, в отличие от man-страницы).самый надежный способ, как предложил Wirawan Purwanto, это проверить
FUNCNAME[1]внутри функции:function mycheck() { declare -p FUNCNAME; } mycheckзатем:
$ bash sourcetest.sh declare -a FUNCNAME='([0]="mycheck" [1]="main")' $ . sourcetest.sh declare -a FUNCNAME='([0]="mycheck" [1]="source")'это эквивалентно проверке производства
callerзначенияmainиsourceразличать контекст вызывающего абонента. ИспользуяFUNCNAME[]сохраняет захват и разборcallerвыход. Вы должны знать или рассчитать свою локальную глубину вызова, чтобы быть правильным, хотя. Такие случаи, как сценарий, получаемый из другой функции или сценария, приведут к тому, что массив (стек) будет глубже. (FUNCNAME- это специальная переменная массива bash, она должна иметь непрерывные индексы, соответствующие стеку вызовов, если она никогда неunset.)function issourced() { [[ ${FUNCNAME[@]: -1} == "source" ]] }(в bash-4.2 и более поздних вы можете использовать более простую форму
${FUNCNAME[-1]}вместо последнего элемента в массиве. Улучшено и упрощено благодаря комментарию Денниса Уильямсона ниже.)однако, ваша проблема, как указано "у меня есть скрипт, где я не хочу, чтобы он называл "выход", если он находится в исходном состоянии". Общее
bashидиома для этой ситуации:return 2>/dev/null || exitесли скрипт находится в исходном состоянии, то
returnзавершит исходный скрипт и вернется к абонент.если скрипт выполняется, то
returnвернет ошибку (перенаправлено), иexitзавершит работу скрипта как обычно. Обаreturnиexitможет принять код выхода, если требуется.к сожалению, это не работает в
ksh(по крайней мере, не в производной версии AT&T у меня здесь), он лечитreturnчто эквивалентноexitесли вызывается вне функции или сценария с точечным источником.Обновлено: что вы можете делать в современных версиях
kshэто проверка специальной переменной.sh.levelкоторый установлен на глубину вызова функции. Для вызванного скрипта это будет изначально не задано, для сценария с точечным источником он будет установлен в 1.function issourced { [[ ${.sh.level} -eq 2 ]] } issourced && echo this script is sourcedэто не совсем так надежно, как версия bash, вы должны вызвать
issourced()в файле, который вы тестируете с верхнего уровня или на известной глубине функции.(вы также можете быть заинтересованы в этот код на github, который использует
kshфункция дисциплины и некоторые отладочные ловушки обмана, чтобы эмулировать БашFUNCNAMEмассив.)канонический ответ здесь:http://mywiki.wooledge.org/BashFAQ/109 также предлагает
$-как еще один индикатор (хотя и несовершенный) состояния оболочки.
Примечания:
- можно создать функции bash с именами " main "и" source" (переопределение строение), эти имена могут появиться в
FUNCNAME[]но пока тестируется только последний элемент в этом массиве, нет никакой двусмысленности.- у меня нет хорошего ответа
pdksh. Самое близкое, что я могу найти, относится только кpdksh, где каждый источник сценария открывает новый файловый дескриптор (начиная с 10 для исходного сценария). Почти наверняка не то, на что вы хотите положиться...
TL; DR
попробуйте выполнить
returnзаявление. Если сценарий не получен, это вызовет ошибку. Вы можете поймать эту ошибку и действовать так, как вам нужно.положите это в файл и назовите его, скажем, test.sh:
#!/usr/bin/env sh # Try to execute a `return` statement, # but do it in a sub-shell and catch the results. # If this script isn't sourced, that will raise an error. $(return >/dev/null 2>&1) # What exit code did that give? if [ "$?" -eq "0" ] then echo "This script is sourced." else echo "This script is not sourced." fiвыполнить его напрямую:
shell-prompt> sh test.sh output: This script is not sourced.источник:
shell-prompt> source test.sh output: This script is sourced.для меня, это работает в zsh и bash.
объяснение
The
returnоператор вызовет ошибку, если вы попытаетесь выполнить его вне функции или если сценарий не является источником. Попробуйте это из командной строки:shell-prompt> return output: ...can only `return` from a function or sourced scriptвам не нужно видеть это сообщение об ошибке, поэтому вы можете перенаправить вывод на dev / null:
shell-prompt> return >/dev/null 2>&1теперь проверьте код выхода. 0 означает OK (ошибок не было), 1 означает, что произошла ошибка:
shell-prompt> echo $? output: 1вы также хотите выполнить
returnзаявление в суб-оболочки. Когдаreturnзаявление запустить его. . . что ж. . . возвращается. Если вы выполнять его в суб-оболочки, он вернется из этой суб-оболочки, а не вернувшихся из вашего сценария. Чтобы выполнить в суб-оболочке, оберните его в$(...):shell-prompt> $(return >/dev/null 2>)теперь вы можете увидеть код выхода суб-оболочки, который должен быть 1, потому что внутри суб-оболочки возникла ошибка:
shell-prompt> echo $? output: 1
Я дам конкретный ответ BASH. Korn-оболочку, к сожалению. Предположим, что имя вашего скрипта
include2.sh; затем сделайте функцию внутри theinclude2.shпод названиемam_I_sourced. Вот моя демо-версияinclude2.sh:am_I_sourced() { if [ "${FUNCNAME[1]}" = source ]; then if [ "" = -v ]; then echo "I am being sourced, this filename is ${BASH_SOURCE[0]} and my caller script/shell name was " fi return 0 else if [ "" = -v ]; then echo "I am not being sourced, my script/shell name was " fi return 1 fi } if am_I_sourced -v; then echo "Do something with sourced script" else echo "Do something with executed script" fiтеперь попробуйте выполнить его во многих отношениях:
~/toys/bash $ chmod a+x include2.sh ~/toys/bash $ ./include2.sh I am not being sourced, my script/shell name was ./include2.sh Do something with executed script ~/toys/bash $ bash ./include2.sh I am not being sourced, my script/shell name was ./include2.sh Do something with executed script ~/toys/bash $ . include2.sh I am being sourced, this filename is include2.sh and my caller script/shell name was bash Do something with sourced scriptтак что это работает без исключения, и он не использует хрупкий
$_вещи. Этот трюк использует средство самоанализа BASH, т. е. встроенные переменныеFUNCNAMEиBASH_SOURCE; увидеть их документация на странице руководства bash.только два нюанса:
1) вызов
am_I_calledдолжны пройдет на исходный скрипт, но не в любая функция, чтобы${FUNCNAME[1]}возвращает что-то другое. Угу...вы могли бы проверить${FUNCNAME[2]}-- но ты только усложняешь свою жизнь.2) Функция
am_I_calledдолжны находиться в исходном скрипте, если вы хотите узнать, каково имя файла быть включенным.
FWIW, прочитав все остальные ответы, я придумал следующее решение для меня:
это работает для всех сценариев, которые начнем с
#!/bin/bashно также могут быть получены из разных оболочек.#!/bin/bash # Function definitions (API) and shell variables (constants) go here main() { # The script's execution part goes here } unset BASH_SOURCE 2>/dev/null test "." != ".$BASH_SOURCE" || main "$@"этот рецепт сценария имеет следующие свойства:
- если выполняется
bash,mainназывается.- если найденный
bash,mainвызывается только в том случае, если вызывающий скрипт имеет такое же имя. (Например, если он сам является источником.)- если источником является оболочка, отличная от
bash,mainэто не называется.- если выполняется оболочкой, отличной от
bash,mainэто не называется.если оценивать
bashСeval(eval "`cat script`"все цитаты важны!) не приходит непосредственно из командной строки, это вызываетmain. Для всех остальных вариантовeval,mainне называемый.если
mainне называется, он возвращаетtrue($?=0).- и это не зависит от недокументированного поведения, которое может измениться.
таким образом, за исключением некоторых маловероятных случаях,
mainвызывается только тогда, когда скрипт выполняется обычным способом. обычно это то, что вы хотите, тем более, что ему не хватает сложного трудного для понимания кода.как
BASH_SOURCEне может быть сбросить вbash, но во всех других оболочках это также ловит крайний случай, гдеBASH_SOURCEимеет значение.обратите внимание, что он очень похож на Python-кода:
if __name__ == '__main__': main()что также предотвращает вызов
main, за исключением некоторых случаев, как вы можете импортировать/загрузить скрипт и применить__name__='__main__'почему я думаю, что это хороший способ решить проблему
если у вас есть что-то, что может быть получено несколькими оболочками, должно быть совместимо. Однако (прочитайте другие ответы),поскольку нет портативного способа обнаружить
sourceing, вы должны изменить правила.путем принудительного выполнения скрипта
/bin/bash, вы именно это и делаете.этой решает все случаи, но после в этом случае скрипт не может работать напрямую:
/bin/bashне установлен или дисфункциональный (т. е. в загрузочной среде)- если вы передаете его в не-Баш-оболочку, как в
curl https://example.com/script | $SHELLздесь$SHELLнеbashоднако я не могу думать о какой-либо реальной причине, где вам это нужно, а также возможность источника точно такой же скрипт параллельно! Обычно вы можете обернуть его, так что сценарий всегда находится в исходном состоянии. Затем выполните
mainвручную. Как что:
sh -c '. script && main'echo 'eval "`curl https://example.com/script`" && main' | $SHELLважно:
последняя работает
mainв два раза, если$SHELLработаетbashи строка не запускается из командной строки. (Но я действительно не могу придумать ни одной причины, по которой вы должны когда-либо использовать это в скрипте, за исключением намеренного обмана кода.)Примечание
этот ответ был бы невозможен без помощи всех другие ответы! Даже неправильные - что заставило меня опубликовать это.
Я хотел бы предложить небольшую поправку к очень полезный ответ Денниса, чтобы сделать его немного более портативный, надеюсь:
[ "$_" != "" ] && echo "Script is being sourced" || echo "Script is a subshell", потому что
[[не признаются (несколько анальный цепкой ИМХО) в Debian POSIX совместимый shell,dash. Кроме того, могут потребоваться кавычки для защиты от имен файлов, содержащих пробелы, опять же в указанной оболочке.
это работает позже в сценарии и никак не зависит от переменной:
## Check to make sure it is not sourced: Prog=myscript.sh if [ $(basename ) = $Prog ]; then exit 1 # not sourced fiили
[ $(basename ) = $Prog ] && exit
$_довольно хрупкие. Вы должны проверить это, как первое, что вы делаете в сценарии. И даже тогда, это не гарантирует, чтобы содержать имя вашей оболочки (если источник) или имя сценария (если выполняется).например, если пользователь установил
BASH_ENV, затем в верхней части скрипта$_содержит имя последней командыBASH_ENVсценарий.лучший способ, который я нашел, это использовать
как это:name="myscript.sh" main() { echo "Script was executed, running main..." } case "" in *$name) main "$@" ;; esacк сожалению, этот способ не работает из коробки в zsh из-за
functionargzeroопция делает больше, чем предполагает ее название, и по умолчанию включена.чтобы обойти это, я поставил
unsetopt functionargzeroв своем.zshenv.
я следовал mklement0 компактное выражение.
это аккуратно, но я заметил, что он может потерпеть неудачу в случае ksh при вызове следующим образом:
/bin/ksh -c ./myscript.sh(он думает, что это источник, и это не потому, что он выполняет подоболочку) Но выражение будет работать, чтобы обнаружить это:
/bin/ksh ./myscript.shкроме того, даже если выражение компактно, синтаксис не совместим со всеми оболочками.
Так что я закончил со следующим кодом, который работает для Баш, ЗШ, тире и КШ
SOURCED=0 if [ -n "$ZSH_EVAL_CONTEXT" ]; then [[ $ZSH_EVAL_CONTEXT =~ :file$ ]] && SOURCED=1 elif [ -n "$KSH_VERSION" ]; then [[ "$(cd $(dirname -- ) && pwd -P)/$(basename -- )" != "$(cd $(dirname -- ${.sh.file}) && pwd -P)/$(basename -- ${.sh.file})" ]] && SOURCED=1 elif [ -n "$BASH_VERSION" ]; then [[ != "$BASH_SOURCE" ]] && SOURCED=1 elif grep -q dash /proc/$$/cmdline; then case in *dash*) SOURCED=1 ;; esac fiне стесняйтесь добавлять поддержку экзотических оболочек:)
Я не думаю, что есть какой-либо портативный способ сделать это как в ksh, так и в bash. В bash вы можете обнаружить его с помощью
callerвыход, но я не думаю, что существует эквивалент в КШ.
Мне нужен был один лайнер, который работает на [mac, linux] с bash.версия >= 3 и ни один из этих ответов не соответствует счету.
[[ ${BASH_SOURCE[0]} = ]] && main "$@"
сразу к делу: вы должны оценить, если переменная "$0" равно имени вашей оболочки.
Вот так:#!/bin/bash echo "First Parameter: " echo if [[ "" == "bash" ]] ; then echo "The script was sourced." else echo "The script WAS NOT sourced." fi
через оболочку:$ bash check_source.sh First Parameter: check_source.sh The script WAS NOT sourced.Через Источник:
$ source check_source.sh First Parameter: bash The script was sourced.
Это довольно трудно иметь 100% портативный способ обнаружения, если сценарий был получен или не.
по моему опыту (7 лет с Шеллскриптинг), единственный безопасный способ (не полагаясь на переменные среды с PIDs и так далее, что не безопасно из-за того, что это что-то переменная), вы должны:
- расширьте возможности вашего if
- используя переключатель / случай, если вы хотите.
оба варианта не могут быть автоматически масштабируется, но это безопаснее путь.
например:
когда вы создаете скрипт через сеанс SSH, значение, возвращаемое переменной "$0" (при использовании источник), составляет Баш.
#!/bin/bash echo "First Parameter: " echo if [[ "" == "bash" || "" == "-bash" ]] ; then echo "The script was sourced." else echo "The script WAS NOT sourced." fiили
#!/bin/bash echo "First Parameter: " echo if [[ "" == "bash" ]] ; then echo "The script was sourced." elif [[ "" == "-bash" ]] ; then echo "The script was sourced via SSH session." else echo "The script WAS NOT sourced." fi
Я закончил с проверкой
[[ $_ == "$(type -p "")" ]]if [[ $_ == "$(type -p "")" ]]; then echo I am invoked from a sub shell else echo I am invoked from a source command fiпри использовании
curl ... | bash -s -- ARGSчтобы запустить удаленный скрипт на лету, $0 будет простоbashвместо нормального/bin/bashпри запуске фактического файла скрипта, поэтому я используюtype -p ""показать полный путь Баш.