Как определить, если сценарий находится в исходном состоянии
у меня есть сценарий, где я не хочу его называть 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=0
zsh (проверено на 5.0.5) - обязательно называть это вне функции
[[ $ZSH_EVAL_CONTEXT =~ :file$ ]] && sourced=1 || sourced=0
cross-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__'
почему я думаю, что это хороший способ решить проблему
если у вас есть что-то, что может быть получено несколькими оболочками, должно быть совместимо. Однако (прочитайте другие ответы),поскольку нет портативного способа обнаружить
source
ing, вы должны изменить правила.путем принудительного выполнения скрипта
/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 ""
показать полный путь Баш.