Итак, я взял этот скрипт из этого руководства: www.tldp.org/LDP/abs/abs-guide.pdf
LOG_DIR=/var/log
ROOT_UID=0
LINES=50
E_XCD=86
E_NOTROOT=87
if [ "$UID" != "$ROOT_UID" ]
then
echo "Must be root to run this script."
exit $E_NOTROOT
fi
if [ -n "$1" ]
then
lines=$1
else
lines=$LINES
fi
cd $LOG_DIR
if [ 'pwd' != "$LOG_DIR" ]
then
echo "Can't change to $LOG_DIR."
exit $E_XCD
fi
Теперь я выполнил sudo su на терминале и вывел $UID, который выдал мне 0. Это означает, что мое условие if оказалось ложным, но я все равно получаю сообщение «Для запуска этого скрипта требуется root» при запуске этого скрипта.
Также в оригинальном сценарии это условие было задано как
if [ "$UID" -ne "$ROOT_UID" ]
но я получал ошибку «Недопустимое число», поскольку, по-видимому, -ne используется только для строк, поэтому я изменил его на !=.
решение1
Вместо того, чтобы выполнить его с помощью
sh script.sh
выполнить его с
bash script.sh
(или добавьте #!/bin/bash
в первую строку для настройки интерпретатора).
Оболочка sh
в Ubuntu — этонет bash
, но отдельная оболочка под названием dash
. dash
не имеет столько функций, как bash
, что делает ее более эффективной, но эти отсутствующие функции иногда ломают скрипты, предназначенные для bash
. Одной из таких функций является $UID
переменная, которая являетсяне определенв dash
.
Это означает, что когда скрипт выполняется в dash
, сравнение станет ["" != "0"]
, что будет оценено как true независимо от того, какой пользователь его запускает. Однако, если он запущен bash
с правами root, строки будут равны, и скрипт будет работать.
решение2
КакМакловин говорит, автоматически устанавливаемая, доступная только для чтения UID
(и EUID
) переменная является особой функциейbash
(и некоторые другие оболочки). Это не стандартно дляРакушки в стиле Борнаи sh
не может предполагаться, что устанавливает эти переменные. В частности, sh
в Ubuntu (в настоящее время, по умолчанию)dash
, который их не устанавливает.
У вас есть два варианта:
- Заставить ваш скрипт запускаться
bash
вместоsh
. - Измените свой скрипт так, чтобы он был более переносимым и не требовал
bash
.
Запуск вашего скрипта с помощьюbash
Вы не сказали нам название вашего сценария (это нормально). Я назову егоcleanup
, так как это название похожего скрипта в руководстве, с которым вы работаете.
Обратите внимание, что янетНазовите его как-то так cleanup.sh
. Это потому, что я не рекомендую вам называть его с .sh
суффиксом:
- Суффикс
.sh
предполагает совместимость сsh
! - Большинству скриптов вообще не дается суффикс, а наличие суффикса
.sh
или.bash
может даже быть интерпретировано как предположение, что ваш файл является «библиотекой», а не скриптом «верхнего уровня». То есть, он предоставляет код, который будет использоваться другими скриптами (например, встроенным.
), а не будет запущен напрямую.
Однако включение .sh
суффикса никак не повлияет на техническое поведение вашего скрипта. Нет никаких технических преимуществ или недостатков, связанных с этим.
Добавитьлиния хэшбэнгакак в самой первой строке вашего скрипта:#!/bin/bash
Сделайте свой скрипт исполняемымс .chmod +x cleanup
Теперь вы можетезапустите свой скриптвыполнив команду:
./cleanup
, когда он находится в текущем каталоге. (Это, пожалуй, самый распространенный способ, особенно при написании сценариев для образования, исследования, тестирования, развлечения или другого ограниченного или одноразового использования.)/path/to/cleanup
, в общем. Если первое слово команды содержит , то/
оно интерпретируется как путь к исполняемому файлу. (Вот почему приведенный выше./
синтаксис.
означает текущий каталог.)Кпервое словоЯ имею в виду команду до, но не включая ее первуюнеэкранированныйпробел или табуляция:
foo-bar/baz
является первым словомfoo-bar/baz qux
, в то время какspam\ ham
является первым словом ,spam\ ham eggs
поскольку пробел перед нимham
экранируется обратной косой чертой.cleanup
, если он находится в каталоге в вашемPATH
(и ни один каталог, указанный первым, не имеет исполняемого файла с таким же именем, и он не замененвстроенная оболочка,функция, илипсевдоним).
Независимо от того, есть ли сценарий или нетcleanup
имеет #!...
строку с хэшбэнгом или что-то в этом роде:
sh cleanup
все равно (попытаюсь) запустить егоsh
в качестве интерпретатора.bash cleanup
все равно (попытаюсь) запустить егоbash
в качестве интерпретатора.
Это потому, что в этих случаях вы фактически запускаете интерпретатор ( sh
или bash
) и передаете имя скрипта интерпретатору для запуска. Многие программы принимают имена файлов для открытия в командной строке, и оболочки, как sh
и bash
следуют этому соглашению.
Сделайте свой скрипт портативным
$UID
Если вы хотите сделать свой скрипт переносимым, самый простой способ — вообще не использовать его , а вместо этого использовать некоторые возможности, доступные всем оболочкам в стиле Bourne.
В общем, нет встроенной оболочки для определения идентификатора пользователя. Но вы можете использоватьid
. Это внешняя программа, а не встроенная в оболочку, но как иcat
иls
, то вполне разумно ожидать, что он будет присутствовать.
id
сам по себе выводит кучу информации, но id -u
выдает только эффективный идентификатор пользователя.
Поэтому вместо if [ "$UID" != "$ROOT_UID" ]
, вы можете использовать:
if [ "$(id -u)" != "$ROOT_UID" ]
Технически, это не эквивалентно. $UID
in bash
дает реальный идентификатор пользователя и id -u
действительно соответствует bash
's $EUID
. Если вам действительно нужен UID, а не EUID, используйте id -ru
.