Простой ответ: Невозможно заставить ваших пользователей использовать ваш сценарий оболочки.
Причина этого довольно проста; сценарий оболочки - это интерпретируемая программа. Это означает, что bash
(или какой-либо другой процесс оболочки) должен прочитать файл для выполнения команд, которые в нем вызываются.
Это, в свою очередь, означает, что пользователь, имеющий разрешение на запуск сценария оболочки, должен иметь разрешение делать все, что делается в сценарии оболочки. В подавляющем большинстве случаев * сценарий оболочки, даже с большим количеством внутренней логики и условных обозначений, при запуске делает то же самое, что и при вводе всего сценария в командную строку, строка за строкой.
Если вы просто пытаетесь помешать необразованным пользователям замедлить работу вашей системы, существует множество способов сделать это , например, то, что предлагает @mikeserv в комментарии к вашему вопросу. Я могу придумать как минимум пять дополнительных способов **, многие из которых можно было бы использовать в комбинации; Важно понимать, что они небезопасны . На самом деле они не запрещают пользователю использовать команду напрямую вместо сценария оболочки, а также не (и не могут) предотвратить создание пользователем собственной копии сценария оболочки ( который он должен иметь права на чтение, чтобы вообще иметь возможность запускать) и изменяет его по своему усмотрению.
Можно написать короткую программу на C для выполнения функции сценария-оболочки, который компилируется в двоичный исполняемый файл, а затем сделать эту программу на C SUID ***, так что это единственный способ пользователь может запустить команду, о которой вы говорите, но это выходит за рамки моей компетенции и моей компетенции.
Другие варианты включают в себя чрезвычайно странные обходные пути (хаки), такие как установка cronjob для изменения вашего файла sudoers, чтобы разрешить запуск команды только в определенное время дня ... но это становится действительно, очень странным и территорией плохих идей.
Я думаю, что стандартный способ сделать это (хотя до сих пор без принуждения технически подкованных пользователей использовать ваш сценарий оболочки) был бы:
(Я сделаю вид, что ограничивающая команда - ] date
.)
date
использует абсолютный путь: / bin / date
(Вы можете узнать, что это за работает с датой
.) Также убедитесь, что ваш сценарий имеет правильный шебанг, чтобы его можно было запустить без необходимости набирать bash ./myscript
, но можно просто запустить как . / myscript
, и убедитесь, что он доступен для чтения и выполнения всем. ( chmod 555 myscript
) / usr / local / bin /
и переименуйте его как date
. / usr / local / bin
в начале их переменной $ PATH
. (Просто войдите в систему как пользователь и запустите echo "$ PATH"
.) У них уже должно быть это по умолчанию.Он не обязательно должен быть в самом начале, если он находится на их пути до / bin
(или независимо от того, где находится исходная команда date
). Если его нет на пути, вы можете добавить его, запустив: echo 'PATH = "/ usr / local / bin: $ PATH"' | sudo tee /etc/profile.d/my_path_prefix.sh
Теперь каждый раз, когда пользователь пытается запустить команду напрямую, он фактически запускает ваш сценарий оболочки, потому что каталог, в котором находится сценарий оболочки, появляется первым в его $ PATH
.
Гораздо более хитрым решением было бы фактически замаскировать исходный двоичный файл, не помещая другую версию ранее в путь для пользователей, а помещая сценарий оболочки вместо самой команды, на прежнем месте. Используйте на свой страх и риск:
bin
, чтобы ни у кого не было ее пути. Вы можете переместить его, например, в / var / local
. (Возможно, есть место получше, но это уже взлом, так что это не имеет большого значения, не так ли?) date
в вашем сценарии-оболочке указывает на новое местоположение для даты
- его абсолютный путь: / var / local / date
в моем примере. date
с исходным именем date
. Главное предостережение заключается в том, что каждый раз, когда кто-либо пытается запустить эту команду, включая системные сценарии инициализации, они вместо этого получат ваш сценарий оболочки.
Это просто взлом, и его нельзя квалифицировать как хорошее системное администрирование. Но это возможно, и вы также можете знать, что это можно сделать. Лучшее решение - это то, что я написал выше.
* Исключения из этого связаны с изменением среды и программ, которые ведут себя по-разному, когда они запускаются в интерактивном режиме по сравнению с тем, когда они запускаются из сценария. Однако эти исключения не имеют ничего общего с разрешениями , поэтому они не имеют отношения к этому обсуждению.
** Если вам интересно, спросите о них в комментариях, и я расскажу о них подробнее.
*** НЕ suid root. Если вы это сделаете, просто создайте пользователя, поместите его в группу, которая является единственной, у которой есть разрешение на запуск команды, о которой вы говорите ( chmod 010
или что-то в этом роде), а затем chown
ваш недавно скомпилированный двоичный файл оболочки должен принадлежать этому пользователю и установить его бит suid с помощью chmod 4511
.
Вы можете использовать старый синтаксис [
if [ -n "$ENV" -a "$ENV" = 'production' ]
(обратите внимание, что я использовал -n
, а не ]! -z
, потому что он читается проще, но это то же самое).
Или мы можем упростить до еще более старого синтаксиса, заставив строку иметь значение:
if [ "x$ENV" = 'xproduction' ]
Наконец, тест -n
может действительно не понадобиться, и вы можете просто выполнить
if [ "$ENV" = 'production' ]
[[...]]
- конструкция оболочки Korn, также поддерживаемая bash
и zsh
, но в остальном не стандартный sh
(и не поддерживается никакими другими оболочками).
busybox
sh
основан на ash
, который реализует подмножество спецификации POSIX sh
(в локали POSIX он по большей части совместим ) с очень небольшим количеством расширений, и, в частности, не с этим.
2019 редактировать . ограниченное подмножество ksh [[...]]
теперь также поддерживается в busybox ash при построении с помощью ASH_TEST
и ASH_BASH_COMPAT
и гораздо большего подмножества в яс
.
В любом случае при написании сценария sh
вы должны придерживаться спецификации POSIX sh
. Скрипты, использующие [[...]]
, должны явно вызывать ksh
, bash
или zsh
. bash
также в основном является оболочкой, совместимой с POSIX sh, но с гораздо большим количеством расширений (включая это).
Проверка того, что x непусто, а затем равняется production
, не имеет большого смысла. Если x == production
, то, очевидно, он не пустой.
Выполняйте сравнение строк с помощью оболочки и утилит POSIX, у вас есть несколько вариантов, наиболее очевидные в данном случае:
утилита [
, известная как test
, обычно встраивается в оболочку:
if ["$ var" = production]; затем
echo PROD
fi
case
конструкция:
case $ var in
production) echo PROD ;;
"") echo EMPTY ;;
*) echo non-PROD ;;
esac
Теперь вы можете проверить, что переменная установить (в отличие от непустого) перед разыменованием его, в случае, если была включена опция существительное
(с set -u
или set -o nounset
или с #! / Bin / sh -u
в качестве строки she-bang), иначе ["$ ENV" = production]
приведет к завершению работы оболочки, если $ ENV
не будет установлено. Для этого вы должны сделать:
if [ "${var+set}" = set ] && [ "$var" = production ]; then
echo PROD
fi
(вам следует избегать оператора -a
[
AND, поскольку он устарел и ненадежен).
Хотя лучший и более канонический способ сделать это:
if [ "${var-}" = production ]; then
echo PROD
fi
nounset
не запускается на $ {var + string}
или $ {var-string}
расширения. $ {var -}
расширяется до содержимого $ var
, если переменная установлена, или до пустой строки в противном случае.
Еще несколько примечаний:
$ ENV
- это специальная переменная для sh
. При запуске в интерактивном режиме он используется как путь к файлу для чтения инициализаций (эквивалент ~ / .bashrc
для bash
). Вы не должны использовать его для других целей.
Вы обнаружите, что в некоторых старых публикациях по сценариям оболочки Unix рекомендуется использовать ["x $ var" = xproduction]
или [production = "x $ var"]
для выполнения сравнение строк. Это было сделано для устранения ошибок в некоторых старых версиях утилиты [
и test
, которые сбивали с толку некоторыми значениями $ var
, например !
, (
или -n
. Это не нужно в современных системах, но кое-что нужно иметь в виду для очень старых систем. В любом случае, случай Конструкция
не имеет такой проблемы.
Другие утилиты POSIX, которые могут выполнять сравнение строк, включают expr
и awk
.
awk_equal() { awk 'BEGIN{exit(!(""ARGV[1] == ""ARGV[2]))}' "$1" "$2"; }
expr_equal() { expr "x $1" = "x $2" > /dev/null; }
if awk_equal "$var" production; then
echo PROD
fi
if expr_equal "$var" production; then
echo PROD
fi
Обратите внимание на необходимость добавления ""
к значениям с awk
, чтобы убедиться, что мы получим сравнение строк (в противном случае 1
будет считаться равным 01
или ] 1e0
) и x
в expr
по той же причине, но также для того, чтобы избежать проблем со значениями, являющимися операторами expr
.
С обоими awk
и expr
(по крайней мере, POSIXly), на самом деле они не являются операторами равенства , а являются проверкой того, имеют ли два операнда одинаковый порядок сортировки, что необязательно то же самое. для я Например, в системе May expr_equal ② ③
возвращает истину, потому что ни ②, ни ③ не имеют определенного порядка сортировки.Некоторые реализации awk
, такие как gawk
, mawk
и busybox awk
, игнорируют это требование POSIX и вместо этого выполняют простое побайтовое сравнение.
В любом случае,Я не могу придумать какой-либо веской причины, по которой вы бы предпочли их [
или случаю
здесь.