В Ubuntu 16.04.3 у меня есть очень простой сценарий удара:
test.sh
[[ 0 == 0 ]] && result="true" || result="false"
echo $result
echo $USER $SHELL $0
Когда я называю его как некорневой пользователь me
или как 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
?
Каждый сценарий начинается с Хижины без него, оболочка, начинающая Ваш сценарий, не знает, какой интерпретатор должен выполнить Ваш script1, и мог бы – как в случае sudo ./script.sh
здесь – выполняет его с sh
, который в Ubuntu 16.04 связан с dash
. Условное выражение [[
a bash
соедините команду, таким образом, dash
не знает, как обработать его и бросает ошибку, с которой Вы встретились.
Решение здесь состоит в том, чтобы добавить
#!/bin/bash
как первая строка Вашего сценария. Можно получить тот же результат при вызове его явно с sudo bash ./script.sh
, но хижина является способом пойти.
Для проверки, какая оболочка запускает скрипт добавить echo $0
к нему. Это не то же как echo $SHELL
, цитирование wiki.archlinux.org:
SHELL содержит путь к предпочтительной оболочке пользователя. Обратите внимание, что это - не обязательно оболочка, которая в настоящее время работает, хотя Bash устанавливает эту переменную на запуске.
1: Поскольку Вы запустили ./test.sh
с bash
это просто приняло bash
, то же идет для sudo su
подоболочка.
Как @dessert объясненный, проблема здесь состоит в том, что Ваш сценарий не имеет строки хижины. Без хижины, sudo
примет значение по умолчанию к попытке выполнить использование файла /bin/sh
. Я не мог найти, что это зарегистрировало где угодно, но я подтвердил путем проверки sudo
исходный код, где я нашел следующее в файле pathnames.h
:
#ifndef _PATH_BSHELL
#define _PATH_BSHELL "/bin/sh"
#endif /* _PATH_BSHELL */
Это означает "набор если переменная _PATH_BSHELL
не определяется, установите его на /bin/sh
". Затем в configure
сценарий включал в источник tarball, мы имеем:
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
Подробно, в этих трех вызовах Вы попробовали:
./test.sh
Нет sudo
; в отсутствие строки хижины Ваша оболочка попытается выполнить сам файл. Так как Вы работаете bash
, это будет эффективно работать bash ./test.sh
и работа.
sudo su
сопровождаемый ./test.sh
.
Здесь, Вы запускаете новую оболочку для пользователя root
. Это будет любой оболочкой, определяется в $SHELL
переменная среды для того пользователя и, на Ubuntu, оболочка корня по умолчанию bash
:
$ grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
sudo ./test.sh
Здесь, Вы позволяете sudo
выполните команду непосредственно. Так как его оболочка по умолчанию /bin/sh
как объяснено выше, это заставляет это запускать скрипт с /bin/sh
, который является dash
и это перестало работать с тех пор dash
не понимает [[
.
Примечание: детали как sudo
наборы оболочка по умолчанию, кажется, немного более сложны. Я пытался изменить файлы, упомянутые в моем ответе для указания на /bin/bash
но sudo
все еще принимал значение по умолчанию к /bin/sh
. Таким образом, должны быть некоторые другие места в исходном коде, где оболочка по умолчанию определяется. Тем не менее, основной момент (это sudo
значения по умолчанию к sh
) все еще стоит.