скрипт bash: разные результаты при вызове с или без sudo


10

В Ubuntu 16.04.3 у меня есть очень простой скрипт bash:

test.sh

[[ 0 == 0 ]] && result="true" || result="false"
echo $result
echo $USER $SHELL $0

Когда я называю это как пользователь без meполномочий root или как root, это работает как ожидалось. Если я использую sudo ./test.sh, он жалуется на синтаксическую ошибку:

$ ./test.sh
true
me /bin/bash ./test.sh

$ sudo su
# ./test.sh 
true
root /bin/bash ./test.sh

# exit
$ sudo ./test.sh
./test.sh: 1: ./test.sh: [[: not found
false
root /bin/bash ./test.sh

Что может быть причиной этого? Как я могу это исправить, чтобы meиспользовать этот скрипт как нормально, так и с sudo?


3
Совет профессионала: бегать не имеет смыслаsudo su . Просто беги sudo -iили sudo -sвзамен.
тердон

@terdon sudo -iменяет местоположение на /root. sudo suили sudo -sне меняйте местоположение каталога.
Джеймс Ньютон

Да, прочитайте вопрос, на который я ссылался ранее, почему И извините, я отредактировал свой предыдущий комментарий, я забыл упомянуть -s.
тердон

Ответы:


20

Каждый сценарий начинается с Shebang , без него оболочка, запускающая ваш сценарий, не знает, какой интерпретатор должен запустить ваш сценарий 1, и может - как в случае sudo ./script.shздесь - запустить его, с shкоторым в Ubuntu 16.04 связано dash. Условное выражение [[ является bashсоставной командой , поэтому dashне знает , как справиться с этим и бросает ошибку вы столкнулись.

Решение здесь состоит в том, чтобы добавить

#!/bin/bash

в первой строке вашего скрипта. Вы можете получить тот же результат, когда вы явно его называете sudo bash ./script.sh, но шебанг - это путь.
Чтобы проверить, какая оболочка запускает ваш скрипт, добавьте echo $0в него. Это не то же самое echo $SHELL , что со ссылкой на wiki.archlinux.org :

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

1: Как вы начали ./test.shс bashэто только предположил , что bash, то же самое относится и к sudo suсубоболочке.


1
Также обратите внимание, что bash запускает скрипт без Шебанга, используя bash, а не /bin/sh.
Муру

@dessert Это исправляет. Спасибо! Как я могу проверить из скрипта, какая оболочка его запускает? ( echo $0Дает мне название сценария: ./test.sh)
Джеймс Ньютон

@JamesNewton нет портативного способа, AFAIK, но вы можете проверить, на что /proc/$$/exeуказывает. Также вы можете тестировать различные переменные, такие как $BASH_VERSION, $ZSH_VERSIONи т. Д. (Но dash не устанавливает такую ​​переменную)
Muru

5

Как объяснил @dessert , проблема в том, что в вашем скрипте нет строки Шебанга . Без шебанга по sudoумолчанию будет пытаться запустить файл с помощью /bin/sh. Я нигде не смог найти документально подтвержденный документ, но я подтвердил, проверив sudoисходный код, где обнаружил в файле следующее pathnames.h:

#ifndef _PATH_BSHELL
#define _PATH_BSHELL "/bin/sh"
#endif /* _PATH_BSHELL */

Это означает «установить, если переменная _PATH_BSHELLне определена, установить ее на /bin/sh». Затем в configureскрипте, включенном в исходный архив, мы имеем:

for p in "/bin/bash" "/usr/bin/sh" "/sbin/sh" "/usr/sbin/sh" "/bin/ksh" "/usr/bin/ksh" "/bin/bash" "/usr/bin/bash"; do
    if test -f "$p"; then
    found=yes
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $p" >&5
$as_echo "$p" >&6; }
    cat >>confdefs.h <<EOF
#define _PATH_BSHELL "$p"
EOF

    break
    fi
done

Этот цикл будет искать /bin/bash, /usr/bin/sh, /sbin/sh, /usr/sbin/shили , /bin/kshа затем устанавливает _PATH_BSHELLв какой был найден первый . Так как /bin/shбыл первым в списке и существует, _PATH_BSHELLустанавливается в /bin/sh. Результатом всего этого является то, что оболочкой по умолчанию, sudoесли не указано иное, является /bin/sh.

Таким образом, по sudoумолчанию будет запускаться что-то с использованием, /bin/shа в Ubuntu, которая является символической ссылкой dash, на минимальную POSIX-совместимую оболочку:

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Feb 27  2015 /bin/sh -> dash

[[Конструкция особенность Баш, оно не определено стандартом POSIX и не понимают dash:

$ bash -c '[[ true ]] && echo yes'
yes
$ dash -c '[[ true ]] && echo yes'
dash: 1: [[: not found

Подробно, в трех вызовах, которые вы пробовали:

  1. ./test.sh

    Нет sudo; в отсутствие строки shebang ваша оболочка попытается выполнить сам файл. Поскольку вы работаете bash, это будет эффективно работать bash ./test.shи работать.

  2. sudo suс последующим ./test.sh.

    Здесь вы запускаете новую оболочку для пользователя root. Это будет оболочка, определенная в $SHELLпеременной окружения для этого пользователя, а в Ubuntu оболочкой root по умолчанию является bash:

    $ grep root /etc/passwd
    root:x:0:0:root:/root:/bin/bash
  3. sudo ./test.sh

    Здесь вы позволяете sudoвыполнить команду напрямую. Поскольку его оболочка по умолчанию такая же, /bin/shкак объяснено выше, это заставляет его запускать сценарий /bin/sh, который dashне работает, поскольку dashне понимает [[.


Примечание : детали того, как sudoустанавливает оболочку по умолчанию, кажутся немного более сложными. Я попытался изменить файлы, упомянутые в моем ответе, чтобы указать, /bin/bashно sudoвсе еще по умолчанию /bin/sh. Поэтому в исходном коде должны быть другие места, где определена оболочка по умолчанию. Тем не менее, главное (что по sudoумолчанию sh) все еще остается в силе.


Я нигде не мог найти документально подтвержденное - я тоже, я просто предполагал, что он будет использовать /bin/shиз сообщения об ошибке - что еще это может быть? Ответ на этот вопрос прекрасно дан в разделе « Какую оболочку использует sudo · SO» , см. Также man sudoраздел «ИСПОЛНЕНИЕ КОМАНД» . Оказывается, sudoне использует промежуточную оболочку !
десерт

1
@dessert yes, он использует собственную реализацию execveсистемного вызова, по умолчанию sh. И нет, промежуточные оболочки не имеют значения, речь идет не об оболочке, которая выполняет команду, а о интерпретаторе оболочки, используемом для чтения данного сценария оболочки. Так что нет, он не запускает промежуточную оболочку, но ему все еще нужен интерпретатор оболочки для сценариев оболочки.
тердон
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.