Как определить, что сценарий получен - PullRequest
167 голосов
/ 21 апреля 2010

У меня есть скрипт, в котором я не хочу, чтобы он вызывал exit, если он получен.

Я думал о проверке, если $0 == bash, но это имеет проблемы, если сценарий получен из другого сценария или если пользователь получает его из другой оболочки, такой как ksh.

Есть ли надежный способ обнаружения, если сценарий получен?

Ответы [ 16 ]

2 голосов
/ 05 апреля 2011

$_ довольно хрупкий. Вы должны проверить это как первое, что вы делаете в сценарии. И даже в этом случае не обязательно будет содержать имя вашей оболочки (если она получена) или имя скрипта (если оно выполнено).

Например, если пользователь установил BASH_ENV, тогда в верхней части скрипта $_ содержит имя последней команды, выполненной в скрипте BASH_ENV.

Лучший способ, который я нашел, это использовать $0 так:

name="myscript.sh"

main()
{
    echo "Script was executed, running main..."
}

case "$0" in *$name)
    main "$@"
    ;;
esac

К сожалению, этот способ не работает из коробки в zsh из-за того, что опция functionargzero делает больше, чем предполагает ее имя, и включена по умолчанию.

Чтобы обойти это, я положил unsetopt functionargzero в свой .zshenv.

1 голос
/ 30 июня 2016

Я следовал mklement0 компактное выражение .

Это здорово, но я заметил, что он может потерпеть неудачу в случае ksh, когда вызывается так:

/bin/ksh -c ./myscript.sh

(он думает, что это источник, а не потому, что он выполняет подоболочку) Но выражение будет работать, чтобы обнаружить это:

/bin/ksh ./myscript.sh

Кроме того, даже если выражение компактно, синтаксис не совместим со всеми оболочками.

Итак, я закончил со следующим кодом, который работает для bash, zsh, dash и ksh

SOURCED=0
if [ -n "$ZSH_EVAL_CONTEXT" ]; then 
    [[ $ZSH_EVAL_CONTEXT =~ :file$ ]] && SOURCED=1
elif [ -n "$KSH_VERSION" ]; then
    [[ "$(cd $(dirname -- $0) && pwd -P)/$(basename -- $0)" != "$(cd $(dirname -- ${.sh.file}) && pwd -P)/$(basename -- ${.sh.file})" ]] && SOURCED=1
elif [ -n "$BASH_VERSION" ]; then
    [[ $0 != "$BASH_SOURCE" ]] && SOURCED=1
elif grep -q dash /proc/$$/cmdline; then
    case $0 in *dash*) SOURCED=1 ;; esac
fi

Не стесняйтесь добавлять поддержку экзотических раковин:)

0 голосов
/ 24 июля 2018

Я закончил проверкой [[ $_ == "$(type -p "$0")" ]]

if [[ $_ == "$(type -p "$0")" ]]; 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 "$0", чтобы показать полный путь bash .

тест:

curl -sSL https://github.com/jjqq2013/bash-scripts/raw/master/common/relpath | bash -s -- /a/b/c/d/e /a/b/CC/DD/EE

source <(curl -sSL https://github.com/jjqq2013/bash-scripts/raw/master/common/relpath)
relpath /a/b/c/d/e /a/b/CC/DD/EE

wget https://github.com/jjqq2013/bash-scripts/raw/master/common/relpath
chmod +x relpath
./relpath /a/b/c/d/e /a/b/CC/DD/EE
0 голосов
/ 11 мая 2017

Прямо к точке: вы должны оценить, равна ли переменная "$ 0" названию вашей оболочки.


Примерно так:

#!/bin/bash

echo "First Parameter: $0"
echo
if [[ "$0" == "bash" ]] ; then
    echo "The script was sourced."
else
    echo "The script WAS NOT sourced."
fi


Через SHELL :

$ bash check_source.sh 
First Parameter: check_source.sh

The script WAS NOT sourced.

Через SOURCE :

$ source check_source.sh
First Parameter: bash

The script was sourced.



Довольно трудно иметь 100% переносимый способ определения, был ли скрипт получен или нет.

Относительно моегоопыт работы (7 лет с Shellscripting) , единственный безопасный способ (не полагаясь на переменные окружения с PID и т. д., который небезопасен из-за того, что это что-то VARIABLE ), вы должны:

  • расширить возможности вашего
  • , используя переключатель / чехол, если хотите.

Оба варианта не могут быть автоматически масштабированы, но это более безопасный способ.



Например:

при создании сценария через сеанс SSH значение retЗначение переменной "$ 0" (при использовании source ) равно -bash .

#!/bin/bash

echo "First Parameter: $0"
echo
if [[ "$0" == "bash" || "$0" == "-bash" ]] ; then
    echo "The script was sourced."
else
    echo "The script WAS NOT sourced."
fi

ИЛИ

#!/bin/bash

echo "First Parameter: $0"
echo
if [[ "$0" == "bash" ]] ; then
    echo "The script was sourced."
elif [[ "$0" == "-bash" ]] ; then
    echo "The script was sourced via SSH session."
else
    echo "The script WAS NOT sourced."
fi
0 голосов
/ 28 февраля 2015

Мне был нужен однострочник, работающий на [mac, linux] с bash.version> = 3, и ни один из этих ответов не отвечал всем требованиям.

[[ ${BASH_SOURCE[0]} = $0 ]] && main "$@"
0 голосов
/ 21 апреля 2010

Я не думаю, что есть какой-либо переносимый способ сделать это как в ksh, так и в bash. В bash вы можете обнаружить его, используя вывод caller, но я не думаю, что в ksh существует эквивалент.

...