Подтвердить что ты не робот

Определение того, была ли выполнена оболочка script "sourcing" it

Возможно ли, чтобы оболочка script проверила, была ли она выполнена через source? То есть, например,

$ source myscript.sh
$ ./myscript.sh

Может ли myscript.sh отличать от этих разных оболочек среды?

4b9b3361

Ответ 1

Я думаю, что Сэм хочет сделать, может быть невозможно.

В какой степени возможно обходное решение с половинным баком, зависит от...

  • ... оболочка пользователей по умолчанию и
  • ... какие альтернативные оболочки им разрешено использовать.

Если я правильно понимаю требования Сэма, он хочет иметь "script", myscript, то есть...

  • ... не напрямую исполняемый файл, вызвав его именем myscript (т.е. имеет chmod a-x);
  • ... не косвенно исполняемый для пользователей путем вызова sh myscript или вызов bash myscript
  • ... только работает с его содержащимися функциями и командами, если их вызывает sourcing it: . myscript

Первыми вещами, которые следует учитывать, являются эти

  • При вызове script непосредственно по его имени (myscript) требуется первая строка в script как #!/bin/bash или аналогичный. Это напрямую определит, какие установленный экземпляр исполняемого файла bash (или символьной ссылки) будет вызываться для запуска script. Это будет новый процесс оболочки. Это требует сам скриптовый файл для установки установленного флага.
  • Запуск script путем вызова двоичного файла оболочки с именем script (путь +) как аргумент (sh myscript), тот же, что и "1". - , за исключением того, что флажок исполняемого файла не нужно устанавливать, а первая строка - hashbang не требуется либо. Единственное, что нужно, это то, что вызов пользователю нужен доступ для чтения к файлу сценария.
  • Вызов script путем поиска его имени файла (. myscript) - это очень то же самое, что и "1." - кроме того, что это не новая оболочка, которая вызывается. Все Команды script выполняются в текущей оболочке, используя ее среду (а также "загрязнение" его среды любыми (новыми) переменными, которые он может установить или изменение. (Обычно это очень опасная вещь: но здесь это может быть используется для выполнения exit $RETURNVALUE при определенных условиях....)

Для "1.":
Легкость в достижении: chmod a-x myscript предотвратит myscript от непосредственно исполняемый файл. Но это не выполнит требования "2." и "3." .

Для '2.' и "3." :
Гораздо труднее достичь. Invokations от sh myscript требуют чтения привилегии для файла. Таким образом, очевидный выход может показаться chmod a-r myscript. Однако это также не разрешит "3." : вы не сможете введите script.

Как насчет написания script таким образом, который использует башизм? Башизм - это конкретный способ сделать то, что другие оболочки не понимают: используя конкретные переменные, команды и т.д. Это можно использовать внутри script для откройте это условие и "сделайте что-нибудь" (например, "display warning.txt", "mailto admin" и т.д.). Но в аду нет способа, чтобы это предотвратило sh или bash или любая другая оболочка от чтения и пытается выполнить все следующие команды/строки, записанные в script, если вы не убили оболочку, вызвав exit.

Примеры: в Bash среда, видимая script, знает $BASH, $BASH_ARGV, $BASH_COMMAND, $BASH_SUBSHELL, BASH_EXECUTION_STRING.... Если вызывается sh (также если источник внутри sh), исполняющая оболочка увидит все эти $BASH_* как пустые переменные среды. Опять же, это можно было бы использовать внутри script, чтобы обнаружить это условие и "сделать что-то"... но не запретить выполнение следующих команд!

Теперь я предполагаю, что...

  • ... script использует #!/bin/bash в качестве первой строки,
  • ... пользователи установили bash в качестве своей оболочки и вызывают команды в следующая таблица из bash, и это их оболочка входа,
  • ... sh доступен, и это символическая ссылка на bash или dash.

Это означает, что возможны следующие вызовы, при этом перечисленные значения для переменных среды

vars+invok   | ./scriptname | sh scriptname | bash scriptname | . scriptname
---------------+--------------+---------------+-----------------+-------------
$0             | ./scriptname | ./scriptname  | ./scriptname    | -bash
$SHLVL         | 2            | 1             | 2               | 1
$SHELLOPTS     | braceexpand: | (empty)       | braceexpand:..  | braceexpand:
$BASH          | /bin/bash    | (empty)       | /bin/bash       | /bin/bash
$BASH_ARGV     | (empty)      | (empty)       | (empty)         | scriptname
$BASH_SUBSHELL | 0            | (empty)       | 0               | 0
$SHELL         | /bin/bash    | /bin/bash     | /bin/bash       | /bin/bash
$OPTARG        | (empty)      | (empty)       | (emtpy)         | (emtpy)

Теперь вы можете поместить логику в свой текст script:

  • Если $0 не равно -bash, тогда выполните exit $SOMERETURNVALUE.

В случае, если script был вызван через sh myscript или bash myscript, тогда он будет выйдите из вызывающей оболочки. В случае, если он был запущен в текущей оболочке, он будет продолжать работать. (Предупреждение: в случае, если script имеет любые другие операторы exit ваша текущая оболочка будет "убита"...)

Итак, введите в свой неисполняемый myscript.txt в начале своего начала что-то вроде это может сделать что-то близкое к вашей цели:

echo BASH=$BASH
test x${BASH} = x/bin/bash && echo "$? :    FINE.... You're using 'bash ...'"
test x${BASH} = x/bin/bash || echo "$? :    RATS !!! -- You're not using BASH and I will kick you out!"
test x${BASH} = x/bin/bash || exit 42
test x"${0}" = x"-bash"    && echo "$? :    FINE.... You've sourced me, and I'm your login shell."
test x"${0}" = x"-bash"    || echo "$? :    RATS !!! -- You've not sourced me (or I'm not your bash login shell) and I will kick you out!"
test x"${0}" = x"-bash"    || exit 33

Ответ 2

Это может быть или не быть тем, чего хотел консультант, но в аналогичной ситуации я хотел, чтобы script указывал, что он предназначен для источника, а не для прямого запуска.

Для достижения этого эффекта мой script читает:

#!/bin/echo Should be run as: source
export SOMEPATH="/some/path/on/my/system"
echo "Your environment has been set up"

Поэтому, когда я запускаю его как команду или источник, я получаю:

$ ./myscript.sh
Should be run as: source ./myscript.sh

$ source ./myscript.sh
Your environment has been set up

Вы можете, конечно, обмануть script, запустив его как sh ./myscript.sh, но по крайней мере он дает правильное ожидаемое поведение в 2 из 3 случаев.

Ответ 3

Это то, что я искал:

[[ ${BASH_SOURCE[0]} = $0 ]] && main "[email protected]"

Ответ 4

Если у вас есть неизменяемый путь к файлу для обычных пользователей, то:

if [ "$(/bin/readlink -f "$0")" = "$KNOWN_PATH_OF_THIS_FILE" ]; then
    # the file was executed
else
    # the file was sourced
fi

(его также можно легко ослабить, чтобы проверить только имя файла или что-то еще).

Но ваши пользователи должны иметь разрешение на чтение, чтобы иметь возможность запускать файл, поэтому абсолютно ничего не мешает им делать то, что они хотят с файлом. Но это может помочь им не использовать его неправильно.

Это решение не зависит от башизмов.

Ответ 6

Да, это возможно. В общем вы можете сделать следующее:

#! /bin/bash                                                                                       

sourced () {
    echo Sourced
}

executed () {
    echo Executed
}

if [[ ${0##*/} == -* ]]; then
    sourced
else
    executed [email protected]
fi

Вывод следующего результата:

$ ./myscript
Executed
$ . ./myscript
Sourced

Ответ 7

Поскольку все наши машины имеют историю, я сделал это:

check_script_call=$(history |tail -1|grep myscript.sh )
if [ -z "$check_script_call" ];then
    echo "This file should be called as a source."
    echo "Please, try again this way:"
    echo "$ source /path/to/myscript.sh"
    exit 1
fi

Каждый раз, когда вы запускаете script (без источника), ваша оболочка создает новый env без истории.

Если вы хотите заботиться о производительности, вы можете попробовать следующее:

if ! history |tail -1|grep set_vars ;then
    echo -e "This file should be called as a source.\n"
    echo "Please, try again this way:"
    echo -e "$ source /path/to/set_vars\n"
    exit 1
fi

PS: Я думаю, что ответ Курта намного более полный, но я думаю, что это могло бы помочь.

Ответ 8

Я еще не могу добавить комментарий (политики стека), поэтому добавляю свой собственный ответ:

Это может работать независимо от того, делаем ли мы:

  • bash scriptname
  • scriptname
  • ./scriptname.

на bash и mksh.

if [ "${0##/*}" == scriptname ]  # if the current name is our script
then
    echo run
else
    echo sourced
fi

Ответ 9

В первом случае $0 будет "myscript.sh". Во втором случае это будет "./myscript". Но, вообще говоря, не было никакого способа сказать source.

Если вы сообщите нам, что вы пытаетесь сделать, вместо того, как вы хотите это сделать, может появиться лучший ответ.