Возможно ли, чтобы оболочка script проверила, была ли она выполнена через source
? То есть, например,
$ source myscript.sh
$ ./myscript.sh
Может ли myscript.sh отличать от этих разных оболочек среды?
Возможно ли, чтобы оболочка script проверила, была ли она выполнена через source
? То есть, например,
$ source myscript.sh
$ ./myscript.sh
Может ли myscript.sh отличать от этих разных оболочек среды?
Я думаю, что Сэм хочет сделать, может быть невозможно.
В какой степени возможно обходное решение с половинным баком, зависит от...
Если я правильно понимаю требования Сэма, он хочет иметь "script",
myscript
, то есть...
myscript
(т.е. имеет chmod a-x
);sh myscript
или
вызов bash myscript
. myscript
Первыми вещами, которые следует учитывать, являются эти
myscript
) требуется первая строка в
script как #!/bin/bash
или аналогичный. Это напрямую определит, какие
установленный экземпляр исполняемого файла bash (или символьной ссылки) будет вызываться для запуска
script. Это будет новый процесс оболочки. Это требует
сам скриптовый файл для установки установленного флага.sh myscript
), тот же, что и "1". - , за исключением того, что
флажок исполняемого файла не нужно устанавливать, а первая строка -
hashbang не требуется либо. Единственное, что нужно, это то, что вызов
пользователю нужен доступ для чтения к файлу сценария.. 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, чтобы обнаружить это условие и "сделать что-то"... но не
запретить выполнение следующих команд!
Теперь я предполагаю, что...
#!/bin/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
Это может быть или не быть тем, чего хотел консультант, но в аналогичной ситуации я хотел, чтобы 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 случаев.
Это то, что я искал:
[[ ${BASH_SOURCE[0]} = $0 ]] && main "[email protected]"
Если у вас есть неизменяемый путь к файлу для обычных пользователей, то:
if [ "$(/bin/readlink -f "$0")" = "$KNOWN_PATH_OF_THIS_FILE" ]; then
# the file was executed
else
# the file was sourced
fi
(его также можно легко ослабить, чтобы проверить только имя файла или что-то еще).
Но ваши пользователи должны иметь разрешение на чтение, чтобы иметь возможность запускать файл, поэтому абсолютно ничего не мешает им делать то, что они хотят с файлом. Но это может помочь им не использовать его неправильно.
Это решение не зависит от башизмов.
На основе Ответ Курта Пфайфлса, это работает для меня
if [ $SHLVL = 1 ]
then
echo 'script was sourced'
fi
Да, это возможно. В общем вы можете сделать следующее:
#! /bin/bash
sourced () {
echo Sourced
}
executed () {
echo Executed
}
if [[ ${0##*/} == -* ]]; then
sourced
else
executed [email protected]
fi
Вывод следующего результата:
$ ./myscript
Executed
$ . ./myscript
Sourced
Поскольку все наши машины имеют историю, я сделал это:
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: Я думаю, что ответ Курта намного более полный, но я думаю, что это могло бы помочь.
Я еще не могу добавить комментарий (политики стека), поэтому добавляю свой собственный ответ:
Это может работать независимо от того, делаем ли мы:
bash scriptname
scriptname
./scriptname
.на bash
и mksh
.
if [ "${0##/*}" == scriptname ] # if the current name is our script
then
echo run
else
echo sourced
fi
В первом случае $0
будет "myscript.sh". Во втором случае это будет "./myscript". Но, вообще говоря, не было никакого способа сказать source
.
Если вы сообщите нам, что вы пытаетесь сделать, вместо того, как вы хотите это сделать, может появиться лучший ответ.