Почему я не могу использовать 'sudo su' в сценарии оболочки? Как заставить скрипт оболочки работать с sudo автоматически

Я не могу понять, что с этим не так. Когда я запускаю его в терминале и ввожу пароль, ничего не происходит, но если я запускаю каждую команду отдельно в терминале, она работает. Спасибо!

#!/bin/bash    

sudo su;
mkdir /opt/D3GO/;
cp `pwd`/D3GO /opt/D3GO/;
cp `pwd`/D3GO.png /opt/D3GO/;
cp `pwd`/D3GO.desktop /usr/share/applications/;
chmod +x /opt/D3GO/D3GO

6 ответов


команда sudo su запускает интерактивную корневую оболочку, но она не преобразует текущую оболочку в корневую.

идиома, чтобы сделать то, что вы хотите, - это что-то вроде этого (спасибо @CharlesDuffy за дополнительную осторожность):

#check for root
UID=$(id -u)
if [ x$UID != x0 ] 
then
    #Beware of how you compose the command
    printf -v cmd_str '%q ' "" "$@"
    exec sudo su -c "$cmd_str"
fi

#I am root
mkdir /opt/D3GO/
#and the rest of your commands

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


sudo su не является командой, выполняемой в оболочке -- it запускает новую оболочку.

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


можно использовать Здесь Документы для перенаправления ввода в интерактивный сценарий оболочки. Оператор << - это инструкция для чтения ввода, пока она не найдет строку, содержащую указанный разделитель, как EOF (конец файла).

sudo su <<EOF
echo "code"
EOF

например

#!/bin/bash    
sudo su <<EOF
mkdir /opt/D3GO/
cp `pwd`/D3GO /opt/D3GO/
cp `pwd`/D3GO.png /opt/D3GO/
cp `pwd`/D3GO.desktop /usr/share/applications/
chmod +x /opt/D3GO/D3GO
EOF

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

[[ $(id -u) -eq 0 ]] || exec sudo /bin/bash -c "$(printf '%q ' "$BASH_SOURCE" "$@")"
  • используя [[ ... ]] вместо [ ... ] делает эту директиву x для операндов (или двойного цитирования LHS) ненужно.

  • используя bash -c вместо su -c для интерпретации реконструированных командная строка делает команду более переносимой, потому что не все платформы поддерживают su -c (например, macOS не делает).

  • на bash, $BASH_SOURCE обычно является более надежным способом ссылки на запущенный скрипт.


при вышеуказанном подходе любые ссылки на переменные или команды / арифметические замены в аргументах неизменно расширяются вызов shell.

если вы вместо вас хотела задержана расширения - так что ссылки на переменные не расширена до sudo shell запускается в контексте root пользователь-используйте это:

(( __reinvoked )) || exec sudo -s __reinvoked=1 "$BASH_SOURCE" "$@"

обратите внимание, что тогда тебе придется один - цитируйте любые аргументы, содержащие ссылки на переменные или замены команд, для которых они должны быть расширены с задержкой; например,'$USER'.

обратите внимание на использование переменной среды ad-hoc __reinvoked для обеспечения re-invocation только один раз (даже если изначально уже вызывается как пользователь root).


здесь скрипт это демонстрирует первую технику:

  • если не запускается как root, скрипт reinvokes с sudo -s, передавая все аргументы через as-is.

  • если ранее не прошел проверку подлинности и все еще в течение периода ожидания,sudo предложит для управляющий пароль.

#!/bin/bash

[[ $(id -u) -eq 0 ]] || exec sudo /bin/bash -c "$(printf '%q ' "$BASH_SOURCE" "$@")"

# Print the username and all arguments.
echo "Running as: $(id -un)"
echo "Arguments:"
for arg; do echo "  $((++i)): [$arg]"; done

полезный ответ acfreitas показывает "сценарий внутри сценария" техника где здесь-документ используется для предоставления кода оболочки через stdin в sudo su.
Опять,sudo -s достаточно и цитирую важен:

sudo -s -H <<'EOF'
echo "$HOME"
EOF

обратите внимание, как открывается здесь-разделитель документов,EOF в данном случае процитировано для того чтобы предотвратить содержание документа от вперед толкование current shell.
Если вы не цитировали (любую часть) EOF, $HOME будет расширяться на current домашний каталог пользователя.

если вы хотите mix вперед и с задержкой расширения, оставьте Открытие здесь-разделитель документа без кавычек и выборочно \кавычки $ случаях:

sudo -s -H <<EOF
echo "Called by: $USER; root's home dir: $HOME"
EOF

потому что запуск "sudo su" открывает новую оболочку, и команда не возвращается, пока вы не выйдете из этой оболочки. Возможно, разделите скрипт на 2 файла: первый запускает sudo и выполняет этот 2-й скрипт под sudo.


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

для исправления попробовать:

в shell-скрипт, попробовать:

su <username> -c "my command"

Итак, если пользователь был "userA":

su userA -c "mkdir /opt/D3GO/"

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

su root -c "mkdir /opt/D3GO/"

вы также можете обойти это путем просто запуск скрипта с sudo в первую очередь

sudo ./myScript.sh

таким образом, скрипт сохраняет исходного пользователя внутри скрипта, к которому вы можете получить доступ, используя стандартные переменные, такие как ${USERNAME}, ${UID} etc

зависит от того, что работает лучше для вас.