Как проверить, работает ли как root в скрипте bash

275

Я пишу сценарий, который требует разрешения корневого уровня, и я хочу сделать так, чтобы, если сценарий не запускался от имени пользователя root, он просто повторял «Пожалуйста, запустите от имени пользователя root». и выходит.

Вот некоторый псевдокод для того, что я ищу:

if (whoami != root)
  then echo "Please run as root"

  else (do stuff)
fi

exit

Как я могу лучше всего (чисто и безопасно) достичь этого? Спасибо!

Ах, просто чтобы уточнить: часть (делать вещи) будет включать запуск команд, которые сами по себе требуют root. Поэтому запуск его как обычного пользователя может привести к ошибке. Это просто предназначено для аккуратного запуска скрипта, требующего корневых команд, без использования sudo внутри скрипта, я просто ищу синтаксический сахар.

Натан
источник
8
(1) сделать его не исполняемым чем-либо еще, тогда root (2) также организует дальнейшие разрешения. (3) id -uвозвращает 0root.
Wrikken

Ответы:

404

Переменная среды $ EUID содержит UID текущего пользователя. UID Root равен 0. Используйте что-то вроде этого в вашем скрипте:

if [ "$EUID" -ne 0 ]
  then echo "Please run as root"
  exit
fi

Примечание: если вы получили, 2: [: Illegal number:проверьте, если у вас есть #!/bin/shв верхней части и измените его на #!/bin/bash.

ptierno
источник
Кажется, что хорошие разрешения и наличие этого - двойной уровень безопасности
Колоб Каньон
25
Я думаю, что лучше сравнить строку со строкой, число с номером. используя двойные скобки, вы можете использовать> напрямую без кавычек [[$ EUID> 0]]
Серхио Абреу
7
Я получил 2: [: Illegal number:предупреждение, пока не изменил его на версию Серхио.
alexeydemin
1
@ thekiwi5000 Точка с запятой требуется только в том случае, если она thenнаходится в той же строке, что и условие ...
ptierno
1
@StephenAngelico Sudo должно работать. Если вы тестируете это с помощью $ sudo echo $ EUID; это плохой тест, и он не пройден, потому что $ EUID раскрывается до того, как команда будет передана в sudo. Попробуйте вставить echo $ EUID в тестовый скрипт и запустить его с помощью sudo.
user1169420
79

В bash-скрипте у вас есть несколько способов проверить, является ли запущенный пользователь root.

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

Я думаю, что лучший способ при использовании bash - использовать $EUIDсо страницы руководства:

EUID   Expands to the effective user ID of the current  user,  initialized
       at shell startup.  This variable is readonly.

Это лучший способ, $UIDкоторый может быть изменен и не отражать реального пользователя, выполняющего скрипт.

if (( $EUID != 0 )); then
    echo "Please run as root"
    exit
fi

Я подхожу к такой проблеме, вводя sudoсвои команды, когда они не запускаются от имени пользователя root. Вот пример:

SUDO=''
if (( $EUID != 0 )); then
    SUDO='sudo'
fi
$SUDO a_command

Таким образом, моя команда запускается пользователем root при использовании суперпользователя или sudoобычным пользователем.

Если ваш скрипт всегда должен запускаться пользователем root, просто установите соответствующие права ( 0500).

sberder
источник
Если человек, который пытается запустить сценарий, не имеет привилегий sudo, это вызовет ошибку и команда не будет запущена? Просто хочу убедиться, я правильно понимаю.
Caperneoignis
1
Я не уверен, что этот ответ на 100% полностью правильный. На RHEL7.2 с использованием Bash 4.2.46 ... если я использую printf $EUIDsudo или нет, я получаю свой UID обратно. Если я использую, id -uя получаю свой UID, и когда я вызываю его с помощью sudo, я получаю 0 обратно. Я сделал что-то не так?
0xSheepdog
4
@ 0xSheepdog, возможно, что в bash cli сначала разрешается расширение переменной $ EUID, а затем sudo меняет пользователя. Поэтому вы получите такое поведение, но в сценариях все будет работать нормально.
Александр Берд
@AlexanderBird Хороший вопрос, спасибо! Я не проводил никаких реальных испытаний, просто сообщил о своем опыте.
0xSheepdog
3
Используйте «herestring» для своего теста, чтобы предотвратить локальное расширение оболочки переменной. Сравните sudo bash <<<'echo $EUID'с bash <<<'echo $EUID'. Больше о heredoc-подобной Herestring на tldp.org/LDP/abs/html/x17837.html
Бруно Броноски
75

Было дано несколько ответов, но, похоже, что лучший способ использовать это:

  • id -u
  • При запуске от имени root вернет идентификатор 0.

Это кажется более надежным, чем другие методы, и кажется, что он возвращает идентификатор 0, даже если сценарий выполняется sudo.

Натан
источник
1
Отлично, это лучший ответ
Дэн Ортега
59
if [[ $(id -u) -ne 0 ]] ; then echo "Please run as root" ; exit 1 ; fi

или

if [[ `id -u` -ne 0 ]] ; then echo "Please run as root" ; exit 1 ; fi

:)

Dale_Reagan
источник
Вы могли бы рассмотреть возможность интеграции ответа Джереми Дж. Старчера с этой частью, в конце концов, это всегда одно и то же ...
действительно,
Я знаю, что из терминала, когда я забываю префикс с чем-то, sudoя могу просто напечатать, sudo !!и это делает работу за меня, вместо того, чтобы нажимать стрелку ВВЕРХ, переходить к началу строки и добавлять sudo вручную. Не уверен, что это вещь BASH или SUDO, но она работает почти все время.
0xSheepdog
@ 0xSheepdog: Это вещь Bash (и особенность некоторых других оболочек, таких как csh, где IIRC она возникла).
Приостановлено до дальнейшего уведомления.
В общем, я бы удалил часть с обратным символом в целом и переписал бы строку ok в if [ "$(id -u)" -ne 0 ]; then echo 'Please run as root.' >&2; exit 1; fi. Приветствия.
LinuxSecurityFreak
29

Как упомянул @wrikken в своих комментариях, id -uгораздо лучше проверять наличие root.

Кроме того, при правильном использовании sudoвы можете проверить скрипт и посмотреть, работает ли он от имени root. Если нет, сделайте так, чтобы он вызывал себя через, sudoа затем запускал с правами root.

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

Джереми Дж. Старчер
источник
Есть ли изящный способ заставить программу вспомнить себя? Возможно, есть какая-то переменная bash с абсолютным путем к программе?
Натан
1
Сейчас я не нахожусь в приглашении BASH для тестирования, но $0у меня есть имя запущенного скрипта. Есть несколько примеров здесь , которые могут помочь вам.
Джереми Дж. Старчер
25

Существует простая проверка для пользователя, являющегося пользователем root.

[[ stuff ]]Синтаксис стандартный способ запуска проверки в Баш.

error() {
  printf '\E[31m'; echo "$@"; printf '\E[0m'
}

if [[ $EUID -eq 0 ]]; then
    error "Do not run this as the root user"
    exit 1
fi

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

Слейтер Викторофф
источник
Что это за errorкоманда? Моя система, кажется, не имеет его. , ,
ruakh
О, это просто маленький талант. Не имеет большого значения, но я приложу это.
Слейтер Викторофф
4
Это круто! Если я могу предложить несколько улучшений: (1) переместить новую строку до конца; (2) записывать в стандартную ошибку, а не в стандартный вывод; (3) устанавливать цвет только в том случае, если стандартная ошибка является терминалом (а не рисковать записью escape-символов в лог-файлы lessили еще что-нибудь); и (4) установить цвет фона, чтобы текст можно было читать независимо от цвета фона терминала пользователя. Итак, как-то так function error () { if [[ -t 2 ]] ; then echo $'\033[31;2;47m'"$@"$'\033[0m' ; else echo "$@" ; fi >&2 ; }. (Tweak по желанию.)
ruakh
3
Разве это не должно быть "-ne" вместо "-eq"?
Карлос Рендон
2
Код @CarlosRendon Slater предназначен для предотвращения запуска чего-либо от имени пользователя root. (Это противоположно тому, о чем просил ФП, но метод проверки будет таким же.)
Джошуа Тейлор,
11

Очень простой способ просто положить:

if [ "$(whoami)" == "root" ] ; then
    # you are root
else
    # you are not root
fi

Преимущество использования этого вместо того id, что вы можете проверить, выполняет ли команда также определенный не-root пользователь; например.

if [ "$(whoami)" == "john" ] ; then
    # you are john
else
    # you are not john
fi
Мэтью Троттер
источник
если вы тестируете пользователя со строкой «root», не разрешаете ли вы запускать кого-либо с именем «root»?
pcarvalho
Вы забыли ";" после if
Triskeldeian
1
@peteroak кто еще будет называться root кроме root?
августа
3
+1 за фактический ответ на вопрос, whoamiа не с использованием id; whoamiкоманда также может быть использована для проверки других пользователей , чем корень, по имени.
Еж
10

0- Читайте официальную документацию по GNU Linux, есть много способов сделать это правильно.

1- убедитесь, что вы поставили подпись оболочки, чтобы избежать ошибок при интерпретации:

 #!/bin/bash

2- это мой сценарий

#!/bin/bash 

if [[ $EUID > 0 ]]; then # we can compare directly with this syntax.
  echo "Please run as root/sudo"
  exit 1
else
  #do your stuff
fi
Серхио Абреу
источник
10

В этом ответе, пусть будет ясно, я предполагаю, что читатель умеет читать bashи сценарии оболочки POSIX, как dash.

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

Тем не менее, если есть что-то, чтобы объяснить дальше, не стесняйтесь комментировать, я сделаю все возможное, чтобы заполнить пробелы.


Оптимизированное универсальное (не только bash) решение для производительности и надежности; совместимы все оболочки

Новое решение:

# bool function to test if the user is root or not
is_user_root () { [ ${EUID:-$(id -u)} -eq 0 ]; }

Тест (сохранить в файл is_user_root__benchmark)

###############################################################################
##                          is_user_root() benchmark                         ##
##                  Bash is fast while Dash is slow in this                  ##
##          Tested with Dash version 0.5.8 and Bash version 4.4.18           ##
##                     Copyright: 2020 Vlastimil Burian                      ##
##                      E-mail: info@vlastimilburian.cz                      ##
##                             License: GPL-3.0                              ##
##                               Revision: 1.0                               ##
###############################################################################

# intentionally, the file does not have executable bit, nor it has no shebang
# to use it, please call the file directly with your shell interpreter like:

# bash is_user_root__benchmark
# dash is_user_root__benchmark

# bool function to test if the user is root or not
is_user_root () { [ ${EUID:-$(id -u)} -eq 0 ]; }

# helper functions
print_time   () { date +"%T.%2N"; }
print_start  () { printf '%s' 'Start  : '; print_time; }
print_finish () { printf '%s' 'Finish : '; print_time; }

readonly iterations=10000

printf '%s\n' '______BENCHMARK_____'
print_start

i=1; while [ $i -lt $iterations ]; do
    is_user_root
    i=$((i + 1))
done

print_finish

Оригинальное решение:

#!/bin/bash

is_user_root()
# function verified to work on Bash version 4.4.18
# both as root and with sudo; and as a normal user
{
    ! (( ${EUID:-0} || $(id -u) ))
}

if is_user_root; then
    echo 'You are the almighty root!'
else
    echo 'You are just an ordinary user.'
fi

^^^ Было доказано, что зачеркнутое решение не ускоряет процесс, но оно существует уже давно, поэтому я буду держать его здесь до тех пор, пока сочту необходимым.


объяснение

Так как читать $EUIDстандартную bashпеременную в разы быстрее , эффективный номер идентификатора пользователя, чем выполнение id -uкоманды для POSIX, - просто найти идентификатор пользователя, это решение объединяет оба в красиво упакованную функцию. Если и только если $EUIDпо какой-либо причине недоступно, id -uкоманда будет выполнена, гарантируя, что мы получим правильное возвращаемое значение независимо от обстоятельств .


Почему я публикую это решение после стольких лет, когда ФП спросил

Что ж, если я правильно вижу, кажется, что выше отсутствует фрагмент кода.

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


Портативное решение POSIX + Пример использования вышеуказанной функции

#!/bin/sh

# bool function to test if the user is root or not (POSIX only)
is_user_root() { [ "$(id -u)" -eq 0 ]; }

if is_user_root; then
    echo 'You are the almighty root!'
    exit 0 # unnecessary, but here it serves the purpose to be explicit for the readers
else
    echo 'You are just an ordinary user.' >&2
    exit 1
fi

Вывод

Как бы вам это ни нравилось, среда Unix / Linux очень разнообразна. Это означает, что есть люди, которые bashтак любят , что даже не думают о переносимости ( POSIX- оболочки). Другие, как я, предпочитают оболочки POSIX . В настоящее время это вопрос личного выбора и потребностей.

LinuxSecurityFreak
источник
6

Если сценарию действительно требуется доступ с правами root, это должно отражать его права доступа к файлу. Наличие корневого скрипта, выполняемого пользователями без полномочий root, будет красным флагом. Я призываю вас не контролировать доступ с помощью ifчека.

chown root:root script.sh
chmod u=rwx,go=r script.sh
Джон Кугельман
источник
4
Если у кого-то есть права доступа, это прекрасно работает, но я чувствую, что чрезмерное использование 777бомбы делает эту проверку немного ошибочной для тех пользователей, которые в первую очередь допустят ошибку.
Слэйтер Викторофф
7
Это предполагает, что пользователь запускает исполняемый скрипт. Если пользователь просто звонит, bash /path/to/scriptего все равно можно o=r
запустить,
5

Один простой способ сделать скрипт доступным только для пользователя root - запустить скрипт со строкой:

#!/bin/su root

alexandre1985
источник
1
Мне любопытно, почему за этот ответ не проголосовали выше? Кажется, самый простой и чистый. Есть ли здесь недостатки?
Басинатор
@Bassinator Я полагаю, что некоторые люди говорят, что он не будет работать на некоторых nix'ах, но до сих пор он работал безупречно на моем Linux. Попытайся! Возможно, этот ответ опоздал на гонку, но я пытаюсь добавить знания, которые просты для сообщества (вместо того, чтобы давать похожие ответы, как большинство в этой теме: /) Проголосуйте, если вам повезло прочитать это и оно работает на твоей машине
alexandre1985
@TamusJRoyce Если цель состоит в том, чтобы проверить, выполняете ли вы от имени пользователя root и не заставляете скрипт запускаться только от имени пользователя root, то почему в каждом ответе после проверки, работает ли от имени пользователя root, они создают сценарий exit? И все же за эти ответы проголосовали? Я предполагаю, что люди неявно не хотят, чтобы скрипт запускался как root. Так что я придерживаюсь этого способа мышления с более простым ответом. Но да, вы также можете узнать из более подробных ответов выше
alexandre1985
@ alexandre1985 Точно. Сценарий: если вы работаете от имени пользователя root, возможно, вы хотите, чтобы скрипт по умолчанию устанавливал программу глобально, когда она спрашивает, как вы хотите ее установить. В противном случае по умолчанию устанавливается локальная установка. Вместо того, чтобы нажимать ввод, пользователь мог выбрать, устанавливать ли он глобально или локально. Но если им нравится значение по умолчанию, они могут нажать Enter. И они не будут предложены с паролем. Ваш шебанг никогда не "проверит", являетесь ли вы пользователем root (для каждого заголовка). Но я все еще думаю, что этот ответ полезен.
TamusJRoyce
@TamusJRoyce полностью оправдывает ваш комментарий. Это действительно проблема, и это решение не для этого варианта использования. Вы открыли мои перспективы. Ты прав. Спасибо
alexandre1985
4

попробуйте следующий код:

if [ "$(id -u)" != "0" ]; then
    echo "Sorry, you are not root."
    exit 1
fi

ИЛИ

if [ `id -u` != "0" ]; then
    echo "Sorry, you are not root."
    exit 1
fi
MLSC
источник
3

Насколько я знаю, правильный способ проверить это:

if [ $(id -u) = "0" ]; then
    echo "You are root"
else
    echo "You are NOT root"
fi

Смотрите раздел «Тестирование на корень» здесь:

http://linuxcommand.org/lc3_wss0080.php

WebBrother
источник
1
заменить = "0"на-eq 0
LinuxSecurityFreak
1
@LinuxSecurityFreak, я заменю его, если вы объясните, почему я должен это делать.
Веб-брат
2

id -uгораздо лучше, чем whoami, так как некоторые системы, такие как Android, могут не предоставлять слово root.

Пример:

# whoami
whoami
whoami: unknown uid 0
Smeterlink
источник
1

Проверьте, являетесь ли вы пользователем root, и выйдите, если вы не:

if ((EUID != 0)); then
    echo "Root or Sudo  Required for script ( $(basename $0) )"
    exit
fi

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

Проверьте, являетесь ли вы пользователем root и, если нет, повышайте его, если возможно

# Fails to create these dirs (needs sudo)
mkdir /test-dir-$(basename $0)
rmdir /test-dir-$(basename $0)

if ((EUID != 0)); then
    echo "Granting root privileges for script ( $(basename $0) )"
    if [[ -t 1 ]]; then
        sudo "$0" "$@"
    else
        exec 1> output_file
        gksu "$0" "$@"
    fi
    exit
fi
echo "Root privileges granted..."
# Creates Dirs as it now has rights
mkdir /test-dir-$(basename $0)
rmdir /test-dir-$(basename $0)
Майк Q
источник
0
#!/bin/bash

# GNU bash, version 4.3.46
# Determine if the user executing this script is the root user or not

# Display the UID
echo "Your UID is ${UID}"

if [ "${UID}" -eq 0 ]
then
    echo "You are root"
else
    echo "You are not root user"
fi

Примечание редактора: если вам не нужны двойные скобки, используйте одинарные для переносимости кода.

Прамод Хараде
источник
3
Вы не объяснили, почему вы предоставили альтернативный ответ на пятилетний вопрос, на который уже есть несколько ответов.
Styphon
-1

Проверьте наличие рута:

ROOT_UID=0   # Root has $UID 0.

if [ "$UID" -eq "$ROOT_UID" ]
then
  echo "You are root."
else
  echo "You are just an ordinary user."
fi

exit 0

Протестировано и работает в корне.

fvillalba89
источник