В 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
?
sudo su
. Просто бегиsudo -i
илиsudo -s
взамен.sudo -i
меняет местоположение на/root
.sudo su
илиsudo -s
не меняйте местоположение каталога.-s
.Ответы:
Каждый сценарий начинается с Shebang , без него оболочка, запускающая ваш сценарий, не знает, какой интерпретатор должен запустить ваш сценарий 1, и может - как в случае
sudo ./script.sh
здесь - запустить его, сsh
которым в Ubuntu 16.04 связаноdash
. Условное выражение[[
являетсяbash
составной командой , поэтомуdash
не знает , как справиться с этим и бросает ошибку вы столкнулись.Решение здесь состоит в том, чтобы добавить
в первой строке вашего скрипта. Вы можете получить тот же результат, когда вы явно его называете
sudo bash ./script.sh
, но шебанг - это путь.Чтобы проверить, какая оболочка запускает ваш скрипт, добавьте
echo $0
в него. Это не то же самоеecho $SHELL
, что со ссылкой на wiki.archlinux.org :1: Как вы начали
./test.sh
сbash
это только предположил , чтоbash
, то же самое относится и кsudo su
субоболочке.источник
/bin/sh
.echo $0
Дает мне название сценария:./test.sh
)/proc/$$/exe
указывает. Также вы можете тестировать различные переменные, такие как$BASH_VERSION
,$ZSH_VERSION
и т. Д. (Но dash не устанавливает такую переменную)Как объяснил @dessert , проблема в том, что в вашем скрипте нет строки Шебанга . Без шебанга по
sudo
умолчанию будет пытаться запустить файл с помощью/bin/sh
. Я нигде не смог найти документально подтвержденный документ, но я подтвердил, проверивsudo
исходный код, где обнаружил в файле следующееpathnames.h
:Это означает «установить, если переменная
_PATH_BSHELL
не определена, установить ее на/bin/sh
». Затем вconfigure
скрипте, включенном в исходный архив, мы имеем:Этот цикл будет искать
/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-совместимую оболочку:[[
Конструкция особенность Баш, оно не определено стандартом POSIX и не понимаютdash
:Подробно, в трех вызовах, которые вы пробовали:
./test.sh
Нет
sudo
; в отсутствие строки shebang ваша оболочка попытается выполнить сам файл. Поскольку вы работаетеbash
, это будет эффективно работатьbash ./test.sh
и работать.sudo su
с последующим./test.sh
.Здесь вы запускаете новую оболочку для пользователя
root
. Это будет оболочка, определенная в$SHELL
переменной окружения для этого пользователя, а в Ubuntu оболочкой root по умолчанию являетсяbash
: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
не использует промежуточную оболочку !execve
системного вызова, по умолчаниюsh
. И нет, промежуточные оболочки не имеют значения, речь идет не об оболочке, которая выполняет команду, а о интерпретаторе оболочки, используемом для чтения данного сценария оболочки. Так что нет, он не запускает промежуточную оболочку, но ему все еще нужен интерпретатор оболочки для сценариев оболочки.